@@ -17176,183 +20391,2506 @@ var _createClass=function(){function defineProperties(target,props){for(var i=0;
*/
/***/ },
-/* 792 */
+/* 882 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_react__ = __webpack_require__(0);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_react__);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_react_redux__ = __webpack_require__(51);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_react_redux___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_react_redux__);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_react_router__ = __webpack_require__(60);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_react_router___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_react_router__);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_semantic_ui_react__ = __webpack_require__(59);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_semantic_ui_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3_semantic_ui_react__);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__actions__ = __webpack_require__(75);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__selectors__ = __webpack_require__(126);
-var _createClass=function(){function defineProperties(target,props){for(var i=0;i
compare*/
/***/ },
-/* 795 */
+/* 885 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_react__ = __webpack_require__(0);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_react__);
-var ShowPlaintext=function ShowPlaintext(props){return __WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement('div',null,__WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement('pre',{style:{whiteSpace:'pre-wrap'}},props.text?props.text:props.diff?diffToPre(props.diff):null));};/* harmony default export */ exports["a"] = ShowPlaintext;function diffToPre(diff){return diff.map(function(part,index){return part.added?__WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement('span',{key:index},__WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement('ins',null,part.value),ifNotNewlineSpace(part.value)):part.removed?__WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement('span',{key:index},__WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement('del',null,part.value),ifNotNewlineSpace(part.value)):__WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement('span',{key:index},part.value,ifNotNewlineSpace(part.value));});}var ifNotNewlineSpace=function ifNotNewlineSpace(str){return!str.endsWith('\n')?' ':'';};
+'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _react=__webpack_require__(0);var _react2=_interopRequireDefault(_react);var _markdownToJsx=__webpack_require__(669);var _markdownToJsx2=_interopRequireDefault(_markdownToJsx);var _dubdiff=__webpack_require__(428);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}var ShowMarkdown=function ShowMarkdown(props){if(props.diff)console.log((0,_dubdiff.diffToString)(props.diff));return _react2.default.createElement('div',null,props.text?(0,_markdownToJsx2.default)(props.text):props.diff?(0,_markdownToJsx2.default)((0,_dubdiff.diffToHtml)(props.diff)):null);};exports.default=ShowMarkdown;
/***/ },
-/* 796 */
+/* 886 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_diff__ = __webpack_require__(421);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_diff___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_diff__);
-/* harmony export (immutable) */ exports["a"] = plaintextDiff;
-/* unused harmony export diffToLogString */
-//!!! this deal with adding and removing spaces could be done more elegantly by
-// diffing on an array of simple data structures that contain the text and the adjacent space
-// the diff would use a custom compare function that would disregard the spaces
-// alternately, the text could be split with the spaces included in the array and then compared with a
-// custom diff function that would treat the space elements as null/ignored
-function plaintextDiff(original,final){var arrOriginal=plaintextSplit(original);var arrFinal=plaintextSplit(final);var diff=__WEBPACK_IMPORTED_MODULE_0_diff__["diffArrays"](arrOriginal,arrFinal);diff=plaintextRestoreSpaces(diff);return diff;}function diffToLogString(diff){return diff.map(function(_ref){var added=_ref.added,removed=_ref.removed,value=_ref.value;var sym=added?"+":removed?'-':'/';return sym+value+sym;});}var plaintextSplit=function plaintextSplit(text){return text.split(/[ ]|(\n)/);};function plaintextRestoreSpaces(diff){return diff.map(function(_ref2){var added=_ref2.added,removed=_ref2.removed,value=_ref2.value;return{added:added,removed:removed,value:value.map(function(str,idx,arr){return str!='\n'&&idxWorld** IDarling** she said
-// the block should be broken up to move the formatting code outside
-// OR the whole formatting string could be brought into the block
-// eg. **Hello WorldDarling** Ishe said
-function rewriteMarkdownDiff(diff){//apply transformation rules
-var transformedDiff=diff;transformedDiff=applyTransformationRule1(transformedDiff);//transformedDiff= applyTransformationRule2(transformedDiff)
-return transformedDiff;}//Transformation rule 1
-// 1. if a multiline del block is followed by an ins block,
-// the first line of the ins block should be inserted at the end of the first line of the del block
-// so the markdown will apply to the ins text as it should
-function applyTransformationRule1(diff){var transformedDiff=[];var B_ADD='added',B_REM='removed',B_SAME='same';var previousBlockType=null;var currentBlockType=null;var previousBlockWasMultiline=false;var currentBlockIsMultiline=false;//iterate the input tokens to create the intermediate representation
-diff.forEach(function(currentBlock){previousBlockType=currentBlockType;previousBlockWasMultiline=currentBlockIsMultiline;currentBlockType=currentBlock.added?B_ADD:currentBlock.removed?B_REMOVED:B_SAME;currentBlockIsMultiline=isMultilineDiffBlock(currentBlock);//transform rule 1 applys when:
-// the previous block was a del and had multiple lines
-// the current block is an ins
-if(previousBlockType==B_REM&¤tBlockType==B_INS&&previousBlockWasMultiline){//split the first line from the current block
-var currentBlockSplit=splitMultilineDiffBlock(currentBlock);//pop the previous diff entry
-var previousBlock=transformedDiff.pop();//split the first line from the previous block
-var previousBlockSplit=splitMultilineDiffBlock(currentBlock);//now add the blocks back, interleaving del and ins blocks
-for(var i=0;i)* - blockquotes (possibly nested)
-// (
-// ([ \t]*#*) - headers
-// |([ \t]+[\*\+-]) - unordered lists
-// |([ \t]+[0-9]+\.) - numeric lists
-// )?
-// [ \t]* - trailing whitespace
-var PREFIX=/^([ \t]*\>)*(([ \t]*#*)|([ \t]*[\*\+-])|([ \t]*[\d]+\.))?[ \t]*/;var transformedDiff=[];return transformedDiff;/// ...
-transform.forEach(function(item){//newlines are undecorated
-if(item.string=='\n'){output+='\n';//flag the new line
-newline=true;//and record the offset in the output string
-newlineIndex=output.length;return;}//wrap del strings with tags
-if(item.state==SDEL){output+=''+item.string+'';//del doesn't reset the newline state
-}//ins strings have to be handled a little differently:
-//if this is an ins just after a newline, or after a del after a newline,
-//we need to peel off any markdown formatting prefixes and insert them at the beginning of the line outside the del/ins tags
-else if(item.state==SINS&&newline){var prestring,poststring;var match=item.string.match(PREFIX);if(match==null)prestring="";else prestring=match[0];poststring=item.string.substring(prestring.length);output=output.substring(0,newlineIndex)+prestring+output.substring(newlineIndex);output+=''+poststring+'';newline=false;newlineIndex=-1;}else if(item.state==SINS){output+=''+item.string+'';}//and just output other strings
-else{output+=item.string;//this resets the newline state
-newline=false;newlineIndex=-1;}});}//returns true if the given diff block contains a newline element
-function isMultilineDiffBlock(_ref3){var value=_ref3.value;return value.find(function(word){return word=='\n';});}//returns an array of diff blocks that have the same added, removed fields as the given one
-//but with the array of words split by newlines
-//if the diff block has no newlines, an array containing only that diff will be returned
-//if the diff block has newlines, the resulting array will have a series of blocks,
-// each of which subsequent to the first block will begin with a newline
-//if the diff block begins with a newline, the returned array will begin with an empty diff
-function splitMultilineDiffBlock(_ref4){var added=_ref4.added,removed=_ref4.removed,value=_ref4.value;//find the indices of the diff block that coorespond to newlines
-var splits=findIndicesOf(value,'\n');//create a range from each index
-var ranges=splits.reduce(//the accumulator is a structure with the last index and the list of ranges
-//the ranges are a {start, end} structure
-function(_ref5,i){var last=_ref5.last,ranges=_ref5.ranges;i,ranges.concat([{start:last,end:i}]);},//start with the zero index and an empty array
-{last:0,ranges:[]}).ranges;//map the ranges into blocks
-var blocks=ranges.map(//each block is the same as the given original block, but with the values split at newlines
-function(_ref6){var start=_ref6.start,end=_ref6.end;added,removed,value.slice(start,end);});return blocks;}//collect all the indices of the given array that satisfy the test function
-var findIndicesOf=function findIndicesOf(array,test){return array.reduce(//add indexes that satisfy the test function to the array
-function(acc,x,i){return test(x)?acc.concat([i]):acc;},//start with the empty array
-[]);};
+'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _react=__webpack_require__(0);var _react2=_interopRequireDefault(_react);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}var ShowPlaintext=function ShowPlaintext(props){return _react2.default.createElement('div',null,_react2.default.createElement('pre',{style:{whiteSpace:'pre-wrap'}},props.text?props.text:props.diff?diffToPre(props.diff):null));};exports.default=ShowPlaintext;function diffToPre(diff){return diff.map(function(part,index){return part.added?_react2.default.createElement('ins',{key:index},part.value):part.removed?_react2.default.createElement('del',{key:index},part.value):_react2.default.createElement('span',{key:index},part.value);});}
/***/ },
-/* 797 */
+/* 887 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_react__ = __webpack_require__(0);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_react___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_react__);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_react_dom__ = __webpack_require__(205);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_react_dom___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_react_dom__);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_redux__ = __webpack_require__(206);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_react_redux__ = __webpack_require__(51);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_react_redux___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3_react_redux__);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4_history_lib_createBrowserHistory__ = __webpack_require__(405);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4_history_lib_createBrowserHistory___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_4_history_lib_createBrowserHistory__);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5_react_router__ = __webpack_require__(60);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5_react_router___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_5_react_router__);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__common_localStore__ = __webpack_require__(406);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__common_reducers__ = __webpack_require__(207);
-/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__common_routes__ = __webpack_require__(407);
-//the localStore implementation is naive
+'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _createClass=function(){function defineProperties(target,props){for(var i=0;i0&&arguments[0]!==undefined?arguments[0]:TOKEN_BOUNDARYS;_classCallCheck(this,EditorsDiff);var _this=_possibleConstructorReturn(this,(EditorsDiff.__proto__||Object.getPrototypeOf(EditorsDiff)).call(this));_this.tokenBoundaries=tokenBoundaries;return _this;}_createClass(EditorsDiff,[{key:'equals',value:function equals(left,right){return left.string==right.string;}//splits the input string into a series of word and punctuation tokens
+//each token is associated with an optional trailing array of spaces
+},{key:'tokenize',value:function tokenize(value){var tokens=value.split(this.tokenBoundaries);var annotatedTokens=[];tokens.forEach(function(token){if(isSpace(token)){if(annotatedTokens.length==0)annotatedTokens.push({string:'',whitespace:[]});var last=annotatedTokens[annotatedTokens.length-1];last.whitespace.push(token);}else{annotatedTokens.push({string:token,whitespace:[]});}});//this final empty token is necessary for the jsdiff diffing engine to work properly
+annotatedTokens.push({string:'',whitespace:[]});return annotatedTokens;}},{key:'join',value:function join(annotatedTokens){var tokens=[];annotatedTokens.forEach(function(annotatedToken){tokens.push(annotatedToken.string);annotatedToken.whitespace.forEach(function(item){tokens.push(item);});});return tokens.join('');}}]);return EditorsDiff;}(_diff.Diff);exports.default=EditorsDiff;var isSpace=function isSpace(str){return /[ ]+/.test(str);};
+
+/***/ },
+/* 888 */
+/***/ function(module, exports) {
+
+module.exports = {
+ "AElig": "Æ",
+ "AMP": "&",
+ "Aacute": "Á",
+ "Acirc": "Â",
+ "Agrave": "À",
+ "Aring": "Å",
+ "Atilde": "Ã",
+ "Auml": "Ä",
+ "COPY": "©",
+ "Ccedil": "Ç",
+ "ETH": "Ð",
+ "Eacute": "É",
+ "Ecirc": "Ê",
+ "Egrave": "È",
+ "Euml": "Ë",
+ "GT": ">",
+ "Iacute": "Í",
+ "Icirc": "Î",
+ "Igrave": "Ì",
+ "Iuml": "Ï",
+ "LT": "<",
+ "Ntilde": "Ñ",
+ "Oacute": "Ó",
+ "Ocirc": "Ô",
+ "Ograve": "Ò",
+ "Oslash": "Ø",
+ "Otilde": "Õ",
+ "Ouml": "Ö",
+ "QUOT": "\"",
+ "REG": "®",
+ "THORN": "Þ",
+ "Uacute": "Ú",
+ "Ucirc": "Û",
+ "Ugrave": "Ù",
+ "Uuml": "Ü",
+ "Yacute": "Ý",
+ "aacute": "á",
+ "acirc": "â",
+ "acute": "´",
+ "aelig": "æ",
+ "agrave": "à",
+ "amp": "&",
+ "aring": "å",
+ "atilde": "ã",
+ "auml": "ä",
+ "brvbar": "¦",
+ "ccedil": "ç",
+ "cedil": "¸",
+ "cent": "¢",
+ "copy": "©",
+ "curren": "¤",
+ "deg": "°",
+ "divide": "÷",
+ "eacute": "é",
+ "ecirc": "ê",
+ "egrave": "è",
+ "eth": "ð",
+ "euml": "ë",
+ "frac12": "½",
+ "frac14": "¼",
+ "frac34": "¾",
+ "gt": ">",
+ "iacute": "í",
+ "icirc": "î",
+ "iexcl": "¡",
+ "igrave": "ì",
+ "iquest": "¿",
+ "iuml": "ï",
+ "laquo": "«",
+ "lt": "<",
+ "macr": "¯",
+ "micro": "µ",
+ "middot": "·",
+ "nbsp": " ",
+ "not": "¬",
+ "ntilde": "ñ",
+ "oacute": "ó",
+ "ocirc": "ô",
+ "ograve": "ò",
+ "ordf": "ª",
+ "ordm": "º",
+ "oslash": "ø",
+ "otilde": "õ",
+ "ouml": "ö",
+ "para": "¶",
+ "plusmn": "±",
+ "pound": "£",
+ "quot": "\"",
+ "raquo": "»",
+ "reg": "®",
+ "sect": "§",
+ "shy": "",
+ "sup1": "¹",
+ "sup2": "²",
+ "sup3": "³",
+ "szlig": "ß",
+ "thorn": "þ",
+ "times": "×",
+ "uacute": "ú",
+ "ucirc": "û",
+ "ugrave": "ù",
+ "uml": "¨",
+ "uuml": "ü",
+ "yacute": "ý",
+ "yen": "¥",
+ "yuml": "ÿ"
+};
+
+/***/ },
+/* 889 */
+/***/ function(module, exports) {
+
+module.exports = {
+ "AEli": "Æ",
+ "AElig": "Æ",
+ "AM": "&",
+ "AMP": "&",
+ "Aacut": "Á",
+ "Aacute": "Á",
+ "Abreve": "Ă",
+ "Acir": "Â",
+ "Acirc": "Â",
+ "Acy": "А",
+ "Afr": "𝔄",
+ "Agrav": "À",
+ "Agrave": "À",
+ "Alpha": "Α",
+ "Amacr": "Ā",
+ "And": "⩓",
+ "Aogon": "Ą",
+ "Aopf": "𝔸",
+ "ApplyFunction": "",
+ "Arin": "Å",
+ "Aring": "Å",
+ "Ascr": "𝒜",
+ "Assign": "≔",
+ "Atild": "Ã",
+ "Atilde": "Ã",
+ "Aum": "Ä",
+ "Auml": "Ä",
+ "Backslash": "∖",
+ "Barv": "⫧",
+ "Barwed": "⌆",
+ "Bcy": "Б",
+ "Because": "∵",
+ "Bernoullis": "ℬ",
+ "Beta": "Β",
+ "Bfr": "𝔅",
+ "Bopf": "𝔹",
+ "Breve": "˘",
+ "Bscr": "ℬ",
+ "Bumpeq": "≎",
+ "CHcy": "Ч",
+ "COP": "©",
+ "COPY": "©",
+ "Cacute": "Ć",
+ "Cap": "⋒",
+ "CapitalDifferentialD": "ⅅ",
+ "Cayleys": "ℭ",
+ "Ccaron": "Č",
+ "Ccedi": "Ç",
+ "Ccedil": "Ç",
+ "Ccirc": "Ĉ",
+ "Cconint": "∰",
+ "Cdot": "Ċ",
+ "Cedilla": "¸",
+ "CenterDot": "·",
+ "Cfr": "ℭ",
+ "Chi": "Χ",
+ "CircleDot": "⊙",
+ "CircleMinus": "⊖",
+ "CirclePlus": "⊕",
+ "CircleTimes": "⊗",
+ "ClockwiseContourIntegral": "∲",
+ "CloseCurlyDoubleQuote": "”",
+ "CloseCurlyQuote": "’",
+ "Colon": "∷",
+ "Colone": "⩴",
+ "Congruent": "≡",
+ "Conint": "∯",
+ "ContourIntegral": "∮",
+ "Copf": "ℂ",
+ "Coproduct": "∐",
+ "CounterClockwiseContourIntegral": "∳",
+ "Cross": "⨯",
+ "Cscr": "𝒞",
+ "Cup": "⋓",
+ "CupCap": "≍",
+ "DD": "ⅅ",
+ "DDotrahd": "⤑",
+ "DJcy": "Ђ",
+ "DScy": "Ѕ",
+ "DZcy": "Џ",
+ "Dagger": "‡",
+ "Darr": "↡",
+ "Dashv": "⫤",
+ "Dcaron": "Ď",
+ "Dcy": "Д",
+ "Del": "∇",
+ "Delta": "Δ",
+ "Dfr": "𝔇",
+ "DiacriticalAcute": "´",
+ "DiacriticalDot": "˙",
+ "DiacriticalDoubleAcute": "˝",
+ "DiacriticalGrave": "`",
+ "DiacriticalTilde": "˜",
+ "Diamond": "⋄",
+ "DifferentialD": "ⅆ",
+ "Dopf": "𝔻",
+ "Dot": "¨",
+ "DotDot": "⃜",
+ "DotEqual": "≐",
+ "DoubleContourIntegral": "∯",
+ "DoubleDot": "¨",
+ "DoubleDownArrow": "⇓",
+ "DoubleLeftArrow": "⇐",
+ "DoubleLeftRightArrow": "⇔",
+ "DoubleLeftTee": "⫤",
+ "DoubleLongLeftArrow": "⟸",
+ "DoubleLongLeftRightArrow": "⟺",
+ "DoubleLongRightArrow": "⟹",
+ "DoubleRightArrow": "⇒",
+ "DoubleRightTee": "⊨",
+ "DoubleUpArrow": "⇑",
+ "DoubleUpDownArrow": "⇕",
+ "DoubleVerticalBar": "∥",
+ "DownArrow": "↓",
+ "DownArrowBar": "⤓",
+ "DownArrowUpArrow": "⇵",
+ "DownBreve": "̑",
+ "DownLeftRightVector": "⥐",
+ "DownLeftTeeVector": "⥞",
+ "DownLeftVector": "↽",
+ "DownLeftVectorBar": "⥖",
+ "DownRightTeeVector": "⥟",
+ "DownRightVector": "⇁",
+ "DownRightVectorBar": "⥗",
+ "DownTee": "⊤",
+ "DownTeeArrow": "↧",
+ "Downarrow": "⇓",
+ "Dscr": "𝒟",
+ "Dstrok": "Đ",
+ "ENG": "Ŋ",
+ "ET": "Ð",
+ "ETH": "Ð",
+ "Eacut": "É",
+ "Eacute": "É",
+ "Ecaron": "Ě",
+ "Ecir": "Ê",
+ "Ecirc": "Ê",
+ "Ecy": "Э",
+ "Edot": "Ė",
+ "Efr": "𝔈",
+ "Egrav": "È",
+ "Egrave": "È",
+ "Element": "∈",
+ "Emacr": "Ē",
+ "EmptySmallSquare": "◻",
+ "EmptyVerySmallSquare": "▫",
+ "Eogon": "Ę",
+ "Eopf": "𝔼",
+ "Epsilon": "Ε",
+ "Equal": "⩵",
+ "EqualTilde": "≂",
+ "Equilibrium": "⇌",
+ "Escr": "ℰ",
+ "Esim": "⩳",
+ "Eta": "Η",
+ "Eum": "Ë",
+ "Euml": "Ë",
+ "Exists": "∃",
+ "ExponentialE": "ⅇ",
+ "Fcy": "Ф",
+ "Ffr": "𝔉",
+ "FilledSmallSquare": "◼",
+ "FilledVerySmallSquare": "▪",
+ "Fopf": "𝔽",
+ "ForAll": "∀",
+ "Fouriertrf": "ℱ",
+ "Fscr": "ℱ",
+ "GJcy": "Ѓ",
+ "G": ">",
+ "GT": ">",
+ "Gamma": "Γ",
+ "Gammad": "Ϝ",
+ "Gbreve": "Ğ",
+ "Gcedil": "Ģ",
+ "Gcirc": "Ĝ",
+ "Gcy": "Г",
+ "Gdot": "Ġ",
+ "Gfr": "𝔊",
+ "Gg": "⋙",
+ "Gopf": "𝔾",
+ "GreaterEqual": "≥",
+ "GreaterEqualLess": "⋛",
+ "GreaterFullEqual": "≧",
+ "GreaterGreater": "⪢",
+ "GreaterLess": "≷",
+ "GreaterSlantEqual": "⩾",
+ "GreaterTilde": "≳",
+ "Gscr": "𝒢",
+ "Gt": "≫",
+ "HARDcy": "Ъ",
+ "Hacek": "ˇ",
+ "Hat": "^",
+ "Hcirc": "Ĥ",
+ "Hfr": "ℌ",
+ "HilbertSpace": "ℋ",
+ "Hopf": "ℍ",
+ "HorizontalLine": "─",
+ "Hscr": "ℋ",
+ "Hstrok": "Ħ",
+ "HumpDownHump": "≎",
+ "HumpEqual": "≏",
+ "IEcy": "Е",
+ "IJlig": "IJ",
+ "IOcy": "Ё",
+ "Iacut": "Í",
+ "Iacute": "Í",
+ "Icir": "Î",
+ "Icirc": "Î",
+ "Icy": "И",
+ "Idot": "İ",
+ "Ifr": "ℑ",
+ "Igrav": "Ì",
+ "Igrave": "Ì",
+ "Im": "ℑ",
+ "Imacr": "Ī",
+ "ImaginaryI": "ⅈ",
+ "Implies": "⇒",
+ "Int": "∬",
+ "Integral": "∫",
+ "Intersection": "⋂",
+ "InvisibleComma": "",
+ "InvisibleTimes": "",
+ "Iogon": "Į",
+ "Iopf": "𝕀",
+ "Iota": "Ι",
+ "Iscr": "ℐ",
+ "Itilde": "Ĩ",
+ "Iukcy": "І",
+ "Ium": "Ï",
+ "Iuml": "Ï",
+ "Jcirc": "Ĵ",
+ "Jcy": "Й",
+ "Jfr": "𝔍",
+ "Jopf": "𝕁",
+ "Jscr": "𝒥",
+ "Jsercy": "Ј",
+ "Jukcy": "Є",
+ "KHcy": "Х",
+ "KJcy": "Ќ",
+ "Kappa": "Κ",
+ "Kcedil": "Ķ",
+ "Kcy": "К",
+ "Kfr": "𝔎",
+ "Kopf": "𝕂",
+ "Kscr": "𝒦",
+ "LJcy": "Љ",
+ "L": "<",
+ "LT": "<",
+ "Lacute": "Ĺ",
+ "Lambda": "Λ",
+ "Lang": "⟪",
+ "Laplacetrf": "ℒ",
+ "Larr": "↞",
+ "Lcaron": "Ľ",
+ "Lcedil": "Ļ",
+ "Lcy": "Л",
+ "LeftAngleBracket": "⟨",
+ "LeftArrow": "←",
+ "LeftArrowBar": "⇤",
+ "LeftArrowRightArrow": "⇆",
+ "LeftCeiling": "⌈",
+ "LeftDoubleBracket": "⟦",
+ "LeftDownTeeVector": "⥡",
+ "LeftDownVector": "⇃",
+ "LeftDownVectorBar": "⥙",
+ "LeftFloor": "⌊",
+ "LeftRightArrow": "↔",
+ "LeftRightVector": "⥎",
+ "LeftTee": "⊣",
+ "LeftTeeArrow": "↤",
+ "LeftTeeVector": "⥚",
+ "LeftTriangle": "⊲",
+ "LeftTriangleBar": "⧏",
+ "LeftTriangleEqual": "⊴",
+ "LeftUpDownVector": "⥑",
+ "LeftUpTeeVector": "⥠",
+ "LeftUpVector": "↿",
+ "LeftUpVectorBar": "⥘",
+ "LeftVector": "↼",
+ "LeftVectorBar": "⥒",
+ "Leftarrow": "⇐",
+ "Leftrightarrow": "⇔",
+ "LessEqualGreater": "⋚",
+ "LessFullEqual": "≦",
+ "LessGreater": "≶",
+ "LessLess": "⪡",
+ "LessSlantEqual": "⩽",
+ "LessTilde": "≲",
+ "Lfr": "𝔏",
+ "Ll": "⋘",
+ "Lleftarrow": "⇚",
+ "Lmidot": "Ŀ",
+ "LongLeftArrow": "⟵",
+ "LongLeftRightArrow": "⟷",
+ "LongRightArrow": "⟶",
+ "Longleftarrow": "⟸",
+ "Longleftrightarrow": "⟺",
+ "Longrightarrow": "⟹",
+ "Lopf": "𝕃",
+ "LowerLeftArrow": "↙",
+ "LowerRightArrow": "↘",
+ "Lscr": "ℒ",
+ "Lsh": "↰",
+ "Lstrok": "Ł",
+ "Lt": "≪",
+ "Map": "⤅",
+ "Mcy": "М",
+ "MediumSpace": " ",
+ "Mellintrf": "ℳ",
+ "Mfr": "𝔐",
+ "MinusPlus": "∓",
+ "Mopf": "𝕄",
+ "Mscr": "ℳ",
+ "Mu": "Μ",
+ "NJcy": "Њ",
+ "Nacute": "Ń",
+ "Ncaron": "Ň",
+ "Ncedil": "Ņ",
+ "Ncy": "Н",
+ "NegativeMediumSpace": "",
+ "NegativeThickSpace": "",
+ "NegativeThinSpace": "",
+ "NegativeVeryThinSpace": "",
+ "NestedGreaterGreater": "≫",
+ "NestedLessLess": "≪",
+ "NewLine": "\n",
+ "Nfr": "𝔑",
+ "NoBreak": "",
+ "NonBreakingSpace": " ",
+ "Nopf": "ℕ",
+ "Not": "⫬",
+ "NotCongruent": "≢",
+ "NotCupCap": "≭",
+ "NotDoubleVerticalBar": "∦",
+ "NotElement": "∉",
+ "NotEqual": "≠",
+ "NotEqualTilde": "≂̸",
+ "NotExists": "∄",
+ "NotGreater": "≯",
+ "NotGreaterEqual": "≱",
+ "NotGreaterFullEqual": "≧̸",
+ "NotGreaterGreater": "≫̸",
+ "NotGreaterLess": "≹",
+ "NotGreaterSlantEqual": "⩾̸",
+ "NotGreaterTilde": "≵",
+ "NotHumpDownHump": "≎̸",
+ "NotHumpEqual": "≏̸",
+ "NotLeftTriangle": "⋪",
+ "NotLeftTriangleBar": "⧏̸",
+ "NotLeftTriangleEqual": "⋬",
+ "NotLess": "≮",
+ "NotLessEqual": "≰",
+ "NotLessGreater": "≸",
+ "NotLessLess": "≪̸",
+ "NotLessSlantEqual": "⩽̸",
+ "NotLessTilde": "≴",
+ "NotNestedGreaterGreater": "⪢̸",
+ "NotNestedLessLess": "⪡̸",
+ "NotPrecedes": "⊀",
+ "NotPrecedesEqual": "⪯̸",
+ "NotPrecedesSlantEqual": "⋠",
+ "NotReverseElement": "∌",
+ "NotRightTriangle": "⋫",
+ "NotRightTriangleBar": "⧐̸",
+ "NotRightTriangleEqual": "⋭",
+ "NotSquareSubset": "⊏̸",
+ "NotSquareSubsetEqual": "⋢",
+ "NotSquareSuperset": "⊐̸",
+ "NotSquareSupersetEqual": "⋣",
+ "NotSubset": "⊂⃒",
+ "NotSubsetEqual": "⊈",
+ "NotSucceeds": "⊁",
+ "NotSucceedsEqual": "⪰̸",
+ "NotSucceedsSlantEqual": "⋡",
+ "NotSucceedsTilde": "≿̸",
+ "NotSuperset": "⊃⃒",
+ "NotSupersetEqual": "⊉",
+ "NotTilde": "≁",
+ "NotTildeEqual": "≄",
+ "NotTildeFullEqual": "≇",
+ "NotTildeTilde": "≉",
+ "NotVerticalBar": "∤",
+ "Nscr": "𝒩",
+ "Ntild": "Ñ",
+ "Ntilde": "Ñ",
+ "Nu": "Ν",
+ "OElig": "Œ",
+ "Oacut": "Ó",
+ "Oacute": "Ó",
+ "Ocir": "Ô",
+ "Ocirc": "Ô",
+ "Ocy": "О",
+ "Odblac": "Ő",
+ "Ofr": "𝔒",
+ "Ograv": "Ò",
+ "Ograve": "Ò",
+ "Omacr": "Ō",
+ "Omega": "Ω",
+ "Omicron": "Ο",
+ "Oopf": "𝕆",
+ "OpenCurlyDoubleQuote": "“",
+ "OpenCurlyQuote": "‘",
+ "Or": "⩔",
+ "Oscr": "𝒪",
+ "Oslas": "Ø",
+ "Oslash": "Ø",
+ "Otild": "Õ",
+ "Otilde": "Õ",
+ "Otimes": "⨷",
+ "Oum": "Ö",
+ "Ouml": "Ö",
+ "OverBar": "‾",
+ "OverBrace": "⏞",
+ "OverBracket": "⎴",
+ "OverParenthesis": "⏜",
+ "PartialD": "∂",
+ "Pcy": "П",
+ "Pfr": "𝔓",
+ "Phi": "Φ",
+ "Pi": "Π",
+ "PlusMinus": "±",
+ "Poincareplane": "ℌ",
+ "Popf": "ℙ",
+ "Pr": "⪻",
+ "Precedes": "≺",
+ "PrecedesEqual": "⪯",
+ "PrecedesSlantEqual": "≼",
+ "PrecedesTilde": "≾",
+ "Prime": "″",
+ "Product": "∏",
+ "Proportion": "∷",
+ "Proportional": "∝",
+ "Pscr": "𝒫",
+ "Psi": "Ψ",
+ "QUO": "\"",
+ "QUOT": "\"",
+ "Qfr": "𝔔",
+ "Qopf": "ℚ",
+ "Qscr": "𝒬",
+ "RBarr": "⤐",
+ "RE": "®",
+ "REG": "®",
+ "Racute": "Ŕ",
+ "Rang": "⟫",
+ "Rarr": "↠",
+ "Rarrtl": "⤖",
+ "Rcaron": "Ř",
+ "Rcedil": "Ŗ",
+ "Rcy": "Р",
+ "Re": "ℜ",
+ "ReverseElement": "∋",
+ "ReverseEquilibrium": "⇋",
+ "ReverseUpEquilibrium": "⥯",
+ "Rfr": "ℜ",
+ "Rho": "Ρ",
+ "RightAngleBracket": "⟩",
+ "RightArrow": "→",
+ "RightArrowBar": "⇥",
+ "RightArrowLeftArrow": "⇄",
+ "RightCeiling": "⌉",
+ "RightDoubleBracket": "⟧",
+ "RightDownTeeVector": "⥝",
+ "RightDownVector": "⇂",
+ "RightDownVectorBar": "⥕",
+ "RightFloor": "⌋",
+ "RightTee": "⊢",
+ "RightTeeArrow": "↦",
+ "RightTeeVector": "⥛",
+ "RightTriangle": "⊳",
+ "RightTriangleBar": "⧐",
+ "RightTriangleEqual": "⊵",
+ "RightUpDownVector": "⥏",
+ "RightUpTeeVector": "⥜",
+ "RightUpVector": "↾",
+ "RightUpVectorBar": "⥔",
+ "RightVector": "⇀",
+ "RightVectorBar": "⥓",
+ "Rightarrow": "⇒",
+ "Ropf": "ℝ",
+ "RoundImplies": "⥰",
+ "Rrightarrow": "⇛",
+ "Rscr": "ℛ",
+ "Rsh": "↱",
+ "RuleDelayed": "⧴",
+ "SHCHcy": "Щ",
+ "SHcy": "Ш",
+ "SOFTcy": "Ь",
+ "Sacute": "Ś",
+ "Sc": "⪼",
+ "Scaron": "Š",
+ "Scedil": "Ş",
+ "Scirc": "Ŝ",
+ "Scy": "С",
+ "Sfr": "𝔖",
+ "ShortDownArrow": "↓",
+ "ShortLeftArrow": "←",
+ "ShortRightArrow": "→",
+ "ShortUpArrow": "↑",
+ "Sigma": "Σ",
+ "SmallCircle": "∘",
+ "Sopf": "𝕊",
+ "Sqrt": "√",
+ "Square": "□",
+ "SquareIntersection": "⊓",
+ "SquareSubset": "⊏",
+ "SquareSubsetEqual": "⊑",
+ "SquareSuperset": "⊐",
+ "SquareSupersetEqual": "⊒",
+ "SquareUnion": "⊔",
+ "Sscr": "𝒮",
+ "Star": "⋆",
+ "Sub": "⋐",
+ "Subset": "⋐",
+ "SubsetEqual": "⊆",
+ "Succeeds": "≻",
+ "SucceedsEqual": "⪰",
+ "SucceedsSlantEqual": "≽",
+ "SucceedsTilde": "≿",
+ "SuchThat": "∋",
+ "Sum": "∑",
+ "Sup": "⋑",
+ "Superset": "⊃",
+ "SupersetEqual": "⊇",
+ "Supset": "⋑",
+ "THOR": "Þ",
+ "THORN": "Þ",
+ "TRADE": "™",
+ "TSHcy": "Ћ",
+ "TScy": "Ц",
+ "Tab": "\t",
+ "Tau": "Τ",
+ "Tcaron": "Ť",
+ "Tcedil": "Ţ",
+ "Tcy": "Т",
+ "Tfr": "𝔗",
+ "Therefore": "∴",
+ "Theta": "Θ",
+ "ThickSpace": " ",
+ "ThinSpace": " ",
+ "Tilde": "∼",
+ "TildeEqual": "≃",
+ "TildeFullEqual": "≅",
+ "TildeTilde": "≈",
+ "Topf": "𝕋",
+ "TripleDot": "⃛",
+ "Tscr": "𝒯",
+ "Tstrok": "Ŧ",
+ "Uacut": "Ú",
+ "Uacute": "Ú",
+ "Uarr": "↟",
+ "Uarrocir": "⥉",
+ "Ubrcy": "Ў",
+ "Ubreve": "Ŭ",
+ "Ucir": "Û",
+ "Ucirc": "Û",
+ "Ucy": "У",
+ "Udblac": "Ű",
+ "Ufr": "𝔘",
+ "Ugrav": "Ù",
+ "Ugrave": "Ù",
+ "Umacr": "Ū",
+ "UnderBar": "_",
+ "UnderBrace": "⏟",
+ "UnderBracket": "⎵",
+ "UnderParenthesis": "⏝",
+ "Union": "⋃",
+ "UnionPlus": "⊎",
+ "Uogon": "Ų",
+ "Uopf": "𝕌",
+ "UpArrow": "↑",
+ "UpArrowBar": "⤒",
+ "UpArrowDownArrow": "⇅",
+ "UpDownArrow": "↕",
+ "UpEquilibrium": "⥮",
+ "UpTee": "⊥",
+ "UpTeeArrow": "↥",
+ "Uparrow": "⇑",
+ "Updownarrow": "⇕",
+ "UpperLeftArrow": "↖",
+ "UpperRightArrow": "↗",
+ "Upsi": "ϒ",
+ "Upsilon": "Υ",
+ "Uring": "Ů",
+ "Uscr": "𝒰",
+ "Utilde": "Ũ",
+ "Uum": "Ü",
+ "Uuml": "Ü",
+ "VDash": "⊫",
+ "Vbar": "⫫",
+ "Vcy": "В",
+ "Vdash": "⊩",
+ "Vdashl": "⫦",
+ "Vee": "⋁",
+ "Verbar": "‖",
+ "Vert": "‖",
+ "VerticalBar": "∣",
+ "VerticalLine": "|",
+ "VerticalSeparator": "❘",
+ "VerticalTilde": "≀",
+ "VeryThinSpace": " ",
+ "Vfr": "𝔙",
+ "Vopf": "𝕍",
+ "Vscr": "𝒱",
+ "Vvdash": "⊪",
+ "Wcirc": "Ŵ",
+ "Wedge": "⋀",
+ "Wfr": "𝔚",
+ "Wopf": "𝕎",
+ "Wscr": "𝒲",
+ "Xfr": "𝔛",
+ "Xi": "Ξ",
+ "Xopf": "𝕏",
+ "Xscr": "𝒳",
+ "YAcy": "Я",
+ "YIcy": "Ї",
+ "YUcy": "Ю",
+ "Yacut": "Ý",
+ "Yacute": "Ý",
+ "Ycirc": "Ŷ",
+ "Ycy": "Ы",
+ "Yfr": "𝔜",
+ "Yopf": "𝕐",
+ "Yscr": "𝒴",
+ "Yuml": "Ÿ",
+ "ZHcy": "Ж",
+ "Zacute": "Ź",
+ "Zcaron": "Ž",
+ "Zcy": "З",
+ "Zdot": "Ż",
+ "ZeroWidthSpace": "",
+ "Zeta": "Ζ",
+ "Zfr": "ℨ",
+ "Zopf": "ℤ",
+ "Zscr": "𝒵",
+ "aacut": "á",
+ "aacute": "á",
+ "abreve": "ă",
+ "ac": "∾",
+ "acE": "∾̳",
+ "acd": "∿",
+ "acir": "â",
+ "acirc": "â",
+ "acut": "´",
+ "acute": "´",
+ "acy": "а",
+ "aeli": "æ",
+ "aelig": "æ",
+ "af": "",
+ "afr": "𝔞",
+ "agrav": "à",
+ "agrave": "à",
+ "alefsym": "ℵ",
+ "aleph": "ℵ",
+ "alpha": "α",
+ "amacr": "ā",
+ "amalg": "⨿",
+ "am": "&",
+ "amp": "&",
+ "and": "∧",
+ "andand": "⩕",
+ "andd": "⩜",
+ "andslope": "⩘",
+ "andv": "⩚",
+ "ang": "∠",
+ "ange": "⦤",
+ "angle": "∠",
+ "angmsd": "∡",
+ "angmsdaa": "⦨",
+ "angmsdab": "⦩",
+ "angmsdac": "⦪",
+ "angmsdad": "⦫",
+ "angmsdae": "⦬",
+ "angmsdaf": "⦭",
+ "angmsdag": "⦮",
+ "angmsdah": "⦯",
+ "angrt": "∟",
+ "angrtvb": "⊾",
+ "angrtvbd": "⦝",
+ "angsph": "∢",
+ "angst": "Å",
+ "angzarr": "⍼",
+ "aogon": "ą",
+ "aopf": "𝕒",
+ "ap": "≈",
+ "apE": "⩰",
+ "apacir": "⩯",
+ "ape": "≊",
+ "apid": "≋",
+ "apos": "'",
+ "approx": "≈",
+ "approxeq": "≊",
+ "arin": "å",
+ "aring": "å",
+ "ascr": "𝒶",
+ "ast": "*",
+ "asymp": "≈",
+ "asympeq": "≍",
+ "atild": "ã",
+ "atilde": "ã",
+ "aum": "ä",
+ "auml": "ä",
+ "awconint": "∳",
+ "awint": "⨑",
+ "bNot": "⫭",
+ "backcong": "≌",
+ "backepsilon": "϶",
+ "backprime": "‵",
+ "backsim": "∽",
+ "backsimeq": "⋍",
+ "barvee": "⊽",
+ "barwed": "⌅",
+ "barwedge": "⌅",
+ "bbrk": "⎵",
+ "bbrktbrk": "⎶",
+ "bcong": "≌",
+ "bcy": "б",
+ "bdquo": "„",
+ "becaus": "∵",
+ "because": "∵",
+ "bemptyv": "⦰",
+ "bepsi": "϶",
+ "bernou": "ℬ",
+ "beta": "β",
+ "beth": "ℶ",
+ "between": "≬",
+ "bfr": "𝔟",
+ "bigcap": "⋂",
+ "bigcirc": "◯",
+ "bigcup": "⋃",
+ "bigodot": "⨀",
+ "bigoplus": "⨁",
+ "bigotimes": "⨂",
+ "bigsqcup": "⨆",
+ "bigstar": "★",
+ "bigtriangledown": "▽",
+ "bigtriangleup": "△",
+ "biguplus": "⨄",
+ "bigvee": "⋁",
+ "bigwedge": "⋀",
+ "bkarow": "⤍",
+ "blacklozenge": "⧫",
+ "blacksquare": "▪",
+ "blacktriangle": "▴",
+ "blacktriangledown": "▾",
+ "blacktriangleleft": "◂",
+ "blacktriangleright": "▸",
+ "blank": "␣",
+ "blk12": "▒",
+ "blk14": "░",
+ "blk34": "▓",
+ "block": "█",
+ "bne": "=⃥",
+ "bnequiv": "≡⃥",
+ "bnot": "⌐",
+ "bopf": "𝕓",
+ "bot": "⊥",
+ "bottom": "⊥",
+ "bowtie": "⋈",
+ "boxDL": "╗",
+ "boxDR": "╔",
+ "boxDl": "╖",
+ "boxDr": "╓",
+ "boxH": "═",
+ "boxHD": "╦",
+ "boxHU": "╩",
+ "boxHd": "╤",
+ "boxHu": "╧",
+ "boxUL": "╝",
+ "boxUR": "╚",
+ "boxUl": "╜",
+ "boxUr": "╙",
+ "boxV": "║",
+ "boxVH": "╬",
+ "boxVL": "╣",
+ "boxVR": "╠",
+ "boxVh": "╫",
+ "boxVl": "╢",
+ "boxVr": "╟",
+ "boxbox": "⧉",
+ "boxdL": "╕",
+ "boxdR": "╒",
+ "boxdl": "┐",
+ "boxdr": "┌",
+ "boxh": "─",
+ "boxhD": "╥",
+ "boxhU": "╨",
+ "boxhd": "┬",
+ "boxhu": "┴",
+ "boxminus": "⊟",
+ "boxplus": "⊞",
+ "boxtimes": "⊠",
+ "boxuL": "╛",
+ "boxuR": "╘",
+ "boxul": "┘",
+ "boxur": "└",
+ "boxv": "│",
+ "boxvH": "╪",
+ "boxvL": "╡",
+ "boxvR": "╞",
+ "boxvh": "┼",
+ "boxvl": "┤",
+ "boxvr": "├",
+ "bprime": "‵",
+ "breve": "˘",
+ "brvba": "¦",
+ "brvbar": "¦",
+ "bscr": "𝒷",
+ "bsemi": "⁏",
+ "bsim": "∽",
+ "bsime": "⋍",
+ "bsol": "\\",
+ "bsolb": "⧅",
+ "bsolhsub": "⟈",
+ "bull": "•",
+ "bullet": "•",
+ "bump": "≎",
+ "bumpE": "⪮",
+ "bumpe": "≏",
+ "bumpeq": "≏",
+ "cacute": "ć",
+ "cap": "∩",
+ "capand": "⩄",
+ "capbrcup": "⩉",
+ "capcap": "⩋",
+ "capcup": "⩇",
+ "capdot": "⩀",
+ "caps": "∩︀",
+ "caret": "⁁",
+ "caron": "ˇ",
+ "ccaps": "⩍",
+ "ccaron": "č",
+ "ccedi": "ç",
+ "ccedil": "ç",
+ "ccirc": "ĉ",
+ "ccups": "⩌",
+ "ccupssm": "⩐",
+ "cdot": "ċ",
+ "cedi": "¸",
+ "cedil": "¸",
+ "cemptyv": "⦲",
+ "cen": "¢",
+ "cent": "¢",
+ "centerdot": "·",
+ "cfr": "𝔠",
+ "chcy": "ч",
+ "check": "✓",
+ "checkmark": "✓",
+ "chi": "χ",
+ "cir": "○",
+ "cirE": "⧃",
+ "circ": "ˆ",
+ "circeq": "≗",
+ "circlearrowleft": "↺",
+ "circlearrowright": "↻",
+ "circledR": "®",
+ "circledS": "Ⓢ",
+ "circledast": "⊛",
+ "circledcirc": "⊚",
+ "circleddash": "⊝",
+ "cire": "≗",
+ "cirfnint": "⨐",
+ "cirmid": "⫯",
+ "cirscir": "⧂",
+ "clubs": "♣",
+ "clubsuit": "♣",
+ "colon": ":",
+ "colone": "≔",
+ "coloneq": "≔",
+ "comma": ",",
+ "commat": "@",
+ "comp": "∁",
+ "compfn": "∘",
+ "complement": "∁",
+ "complexes": "ℂ",
+ "cong": "≅",
+ "congdot": "⩭",
+ "conint": "∮",
+ "copf": "𝕔",
+ "coprod": "∐",
+ "cop": "©",
+ "copy": "©",
+ "copysr": "℗",
+ "crarr": "↵",
+ "cross": "✗",
+ "cscr": "𝒸",
+ "csub": "⫏",
+ "csube": "⫑",
+ "csup": "⫐",
+ "csupe": "⫒",
+ "ctdot": "⋯",
+ "cudarrl": "⤸",
+ "cudarrr": "⤵",
+ "cuepr": "⋞",
+ "cuesc": "⋟",
+ "cularr": "↶",
+ "cularrp": "⤽",
+ "cup": "∪",
+ "cupbrcap": "⩈",
+ "cupcap": "⩆",
+ "cupcup": "⩊",
+ "cupdot": "⊍",
+ "cupor": "⩅",
+ "cups": "∪︀",
+ "curarr": "↷",
+ "curarrm": "⤼",
+ "curlyeqprec": "⋞",
+ "curlyeqsucc": "⋟",
+ "curlyvee": "⋎",
+ "curlywedge": "⋏",
+ "curre": "¤",
+ "curren": "¤",
+ "curvearrowleft": "↶",
+ "curvearrowright": "↷",
+ "cuvee": "⋎",
+ "cuwed": "⋏",
+ "cwconint": "∲",
+ "cwint": "∱",
+ "cylcty": "⌭",
+ "dArr": "⇓",
+ "dHar": "⥥",
+ "dagger": "†",
+ "daleth": "ℸ",
+ "darr": "↓",
+ "dash": "‐",
+ "dashv": "⊣",
+ "dbkarow": "⤏",
+ "dblac": "˝",
+ "dcaron": "ď",
+ "dcy": "д",
+ "dd": "ⅆ",
+ "ddagger": "‡",
+ "ddarr": "⇊",
+ "ddotseq": "⩷",
+ "de": "°",
+ "deg": "°",
+ "delta": "δ",
+ "demptyv": "⦱",
+ "dfisht": "⥿",
+ "dfr": "𝔡",
+ "dharl": "⇃",
+ "dharr": "⇂",
+ "diam": "⋄",
+ "diamond": "⋄",
+ "diamondsuit": "♦",
+ "diams": "♦",
+ "die": "¨",
+ "digamma": "ϝ",
+ "disin": "⋲",
+ "div": "÷",
+ "divid": "÷",
+ "divide": "÷",
+ "divideontimes": "⋇",
+ "divonx": "⋇",
+ "djcy": "ђ",
+ "dlcorn": "⌞",
+ "dlcrop": "⌍",
+ "dollar": "$",
+ "dopf": "𝕕",
+ "dot": "˙",
+ "doteq": "≐",
+ "doteqdot": "≑",
+ "dotminus": "∸",
+ "dotplus": "∔",
+ "dotsquare": "⊡",
+ "doublebarwedge": "⌆",
+ "downarrow": "↓",
+ "downdownarrows": "⇊",
+ "downharpoonleft": "⇃",
+ "downharpoonright": "⇂",
+ "drbkarow": "⤐",
+ "drcorn": "⌟",
+ "drcrop": "⌌",
+ "dscr": "𝒹",
+ "dscy": "ѕ",
+ "dsol": "⧶",
+ "dstrok": "đ",
+ "dtdot": "⋱",
+ "dtri": "▿",
+ "dtrif": "▾",
+ "duarr": "⇵",
+ "duhar": "⥯",
+ "dwangle": "⦦",
+ "dzcy": "џ",
+ "dzigrarr": "⟿",
+ "eDDot": "⩷",
+ "eDot": "≑",
+ "eacut": "é",
+ "eacute": "é",
+ "easter": "⩮",
+ "ecaron": "ě",
+ "ecir": "ê",
+ "ecirc": "ê",
+ "ecolon": "≕",
+ "ecy": "э",
+ "edot": "ė",
+ "ee": "ⅇ",
+ "efDot": "≒",
+ "efr": "𝔢",
+ "eg": "⪚",
+ "egrav": "è",
+ "egrave": "è",
+ "egs": "⪖",
+ "egsdot": "⪘",
+ "el": "⪙",
+ "elinters": "⏧",
+ "ell": "ℓ",
+ "els": "⪕",
+ "elsdot": "⪗",
+ "emacr": "ē",
+ "empty": "∅",
+ "emptyset": "∅",
+ "emptyv": "∅",
+ "emsp13": " ",
+ "emsp14": " ",
+ "emsp": " ",
+ "eng": "ŋ",
+ "ensp": " ",
+ "eogon": "ę",
+ "eopf": "𝕖",
+ "epar": "⋕",
+ "eparsl": "⧣",
+ "eplus": "⩱",
+ "epsi": "ε",
+ "epsilon": "ε",
+ "epsiv": "ϵ",
+ "eqcirc": "≖",
+ "eqcolon": "≕",
+ "eqsim": "≂",
+ "eqslantgtr": "⪖",
+ "eqslantless": "⪕",
+ "equals": "=",
+ "equest": "≟",
+ "equiv": "≡",
+ "equivDD": "⩸",
+ "eqvparsl": "⧥",
+ "erDot": "≓",
+ "erarr": "⥱",
+ "escr": "ℯ",
+ "esdot": "≐",
+ "esim": "≂",
+ "eta": "η",
+ "et": "ð",
+ "eth": "ð",
+ "eum": "ë",
+ "euml": "ë",
+ "euro": "€",
+ "excl": "!",
+ "exist": "∃",
+ "expectation": "ℰ",
+ "exponentiale": "ⅇ",
+ "fallingdotseq": "≒",
+ "fcy": "ф",
+ "female": "♀",
+ "ffilig": "ffi",
+ "fflig": "ff",
+ "ffllig": "ffl",
+ "ffr": "𝔣",
+ "filig": "fi",
+ "fjlig": "fj",
+ "flat": "♭",
+ "fllig": "fl",
+ "fltns": "▱",
+ "fnof": "ƒ",
+ "fopf": "𝕗",
+ "forall": "∀",
+ "fork": "⋔",
+ "forkv": "⫙",
+ "fpartint": "⨍",
+ "frac1": "¼",
+ "frac12": "½",
+ "frac13": "⅓",
+ "frac14": "¼",
+ "frac15": "⅕",
+ "frac16": "⅙",
+ "frac18": "⅛",
+ "frac23": "⅔",
+ "frac25": "⅖",
+ "frac3": "¾",
+ "frac34": "¾",
+ "frac35": "⅗",
+ "frac38": "⅜",
+ "frac45": "⅘",
+ "frac56": "⅚",
+ "frac58": "⅝",
+ "frac78": "⅞",
+ "frasl": "⁄",
+ "frown": "⌢",
+ "fscr": "𝒻",
+ "gE": "≧",
+ "gEl": "⪌",
+ "gacute": "ǵ",
+ "gamma": "γ",
+ "gammad": "ϝ",
+ "gap": "⪆",
+ "gbreve": "ğ",
+ "gcirc": "ĝ",
+ "gcy": "г",
+ "gdot": "ġ",
+ "ge": "≥",
+ "gel": "⋛",
+ "geq": "≥",
+ "geqq": "≧",
+ "geqslant": "⩾",
+ "ges": "⩾",
+ "gescc": "⪩",
+ "gesdot": "⪀",
+ "gesdoto": "⪂",
+ "gesdotol": "⪄",
+ "gesl": "⋛︀",
+ "gesles": "⪔",
+ "gfr": "𝔤",
+ "gg": "≫",
+ "ggg": "⋙",
+ "gimel": "ℷ",
+ "gjcy": "ѓ",
+ "gl": "≷",
+ "glE": "⪒",
+ "gla": "⪥",
+ "glj": "⪤",
+ "gnE": "≩",
+ "gnap": "⪊",
+ "gnapprox": "⪊",
+ "gne": "⪈",
+ "gneq": "⪈",
+ "gneqq": "≩",
+ "gnsim": "⋧",
+ "gopf": "𝕘",
+ "grave": "`",
+ "gscr": "ℊ",
+ "gsim": "≳",
+ "gsime": "⪎",
+ "gsiml": "⪐",
+ "g": ">",
+ "gt": ">",
+ "gtcc": "⪧",
+ "gtcir": "⩺",
+ "gtdot": "⋗",
+ "gtlPar": "⦕",
+ "gtquest": "⩼",
+ "gtrapprox": "⪆",
+ "gtrarr": "⥸",
+ "gtrdot": "⋗",
+ "gtreqless": "⋛",
+ "gtreqqless": "⪌",
+ "gtrless": "≷",
+ "gtrsim": "≳",
+ "gvertneqq": "≩︀",
+ "gvnE": "≩︀",
+ "hArr": "⇔",
+ "hairsp": " ",
+ "half": "½",
+ "hamilt": "ℋ",
+ "hardcy": "ъ",
+ "harr": "↔",
+ "harrcir": "⥈",
+ "harrw": "↭",
+ "hbar": "ℏ",
+ "hcirc": "ĥ",
+ "hearts": "♥",
+ "heartsuit": "♥",
+ "hellip": "…",
+ "hercon": "⊹",
+ "hfr": "𝔥",
+ "hksearow": "⤥",
+ "hkswarow": "⤦",
+ "hoarr": "⇿",
+ "homtht": "∻",
+ "hookleftarrow": "↩",
+ "hookrightarrow": "↪",
+ "hopf": "𝕙",
+ "horbar": "―",
+ "hscr": "𝒽",
+ "hslash": "ℏ",
+ "hstrok": "ħ",
+ "hybull": "⁃",
+ "hyphen": "‐",
+ "iacut": "í",
+ "iacute": "í",
+ "ic": "",
+ "icir": "î",
+ "icirc": "î",
+ "icy": "и",
+ "iecy": "е",
+ "iexc": "¡",
+ "iexcl": "¡",
+ "iff": "⇔",
+ "ifr": "𝔦",
+ "igrav": "ì",
+ "igrave": "ì",
+ "ii": "ⅈ",
+ "iiiint": "⨌",
+ "iiint": "∭",
+ "iinfin": "⧜",
+ "iiota": "℩",
+ "ijlig": "ij",
+ "imacr": "ī",
+ "image": "ℑ",
+ "imagline": "ℐ",
+ "imagpart": "ℑ",
+ "imath": "ı",
+ "imof": "⊷",
+ "imped": "Ƶ",
+ "in": "∈",
+ "incare": "℅",
+ "infin": "∞",
+ "infintie": "⧝",
+ "inodot": "ı",
+ "int": "∫",
+ "intcal": "⊺",
+ "integers": "ℤ",
+ "intercal": "⊺",
+ "intlarhk": "⨗",
+ "intprod": "⨼",
+ "iocy": "ё",
+ "iogon": "į",
+ "iopf": "𝕚",
+ "iota": "ι",
+ "iprod": "⨼",
+ "iques": "¿",
+ "iquest": "¿",
+ "iscr": "𝒾",
+ "isin": "∈",
+ "isinE": "⋹",
+ "isindot": "⋵",
+ "isins": "⋴",
+ "isinsv": "⋳",
+ "isinv": "∈",
+ "it": "",
+ "itilde": "ĩ",
+ "iukcy": "і",
+ "ium": "ï",
+ "iuml": "ï",
+ "jcirc": "ĵ",
+ "jcy": "й",
+ "jfr": "𝔧",
+ "jmath": "ȷ",
+ "jopf": "𝕛",
+ "jscr": "𝒿",
+ "jsercy": "ј",
+ "jukcy": "є",
+ "kappa": "κ",
+ "kappav": "ϰ",
+ "kcedil": "ķ",
+ "kcy": "к",
+ "kfr": "𝔨",
+ "kgreen": "ĸ",
+ "khcy": "х",
+ "kjcy": "ќ",
+ "kopf": "𝕜",
+ "kscr": "𝓀",
+ "lAarr": "⇚",
+ "lArr": "⇐",
+ "lAtail": "⤛",
+ "lBarr": "⤎",
+ "lE": "≦",
+ "lEg": "⪋",
+ "lHar": "⥢",
+ "lacute": "ĺ",
+ "laemptyv": "⦴",
+ "lagran": "ℒ",
+ "lambda": "λ",
+ "lang": "⟨",
+ "langd": "⦑",
+ "langle": "⟨",
+ "lap": "⪅",
+ "laqu": "«",
+ "laquo": "«",
+ "larr": "←",
+ "larrb": "⇤",
+ "larrbfs": "⤟",
+ "larrfs": "⤝",
+ "larrhk": "↩",
+ "larrlp": "↫",
+ "larrpl": "⤹",
+ "larrsim": "⥳",
+ "larrtl": "↢",
+ "lat": "⪫",
+ "latail": "⤙",
+ "late": "⪭",
+ "lates": "⪭︀",
+ "lbarr": "⤌",
+ "lbbrk": "❲",
+ "lbrace": "{",
+ "lbrack": "[",
+ "lbrke": "⦋",
+ "lbrksld": "⦏",
+ "lbrkslu": "⦍",
+ "lcaron": "ľ",
+ "lcedil": "ļ",
+ "lceil": "⌈",
+ "lcub": "{",
+ "lcy": "л",
+ "ldca": "⤶",
+ "ldquo": "“",
+ "ldquor": "„",
+ "ldrdhar": "⥧",
+ "ldrushar": "⥋",
+ "ldsh": "↲",
+ "le": "≤",
+ "leftarrow": "←",
+ "leftarrowtail": "↢",
+ "leftharpoondown": "↽",
+ "leftharpoonup": "↼",
+ "leftleftarrows": "⇇",
+ "leftrightarrow": "↔",
+ "leftrightarrows": "⇆",
+ "leftrightharpoons": "⇋",
+ "leftrightsquigarrow": "↭",
+ "leftthreetimes": "⋋",
+ "leg": "⋚",
+ "leq": "≤",
+ "leqq": "≦",
+ "leqslant": "⩽",
+ "les": "⩽",
+ "lescc": "⪨",
+ "lesdot": "⩿",
+ "lesdoto": "⪁",
+ "lesdotor": "⪃",
+ "lesg": "⋚︀",
+ "lesges": "⪓",
+ "lessapprox": "⪅",
+ "lessdot": "⋖",
+ "lesseqgtr": "⋚",
+ "lesseqqgtr": "⪋",
+ "lessgtr": "≶",
+ "lesssim": "≲",
+ "lfisht": "⥼",
+ "lfloor": "⌊",
+ "lfr": "𝔩",
+ "lg": "≶",
+ "lgE": "⪑",
+ "lhard": "↽",
+ "lharu": "↼",
+ "lharul": "⥪",
+ "lhblk": "▄",
+ "ljcy": "љ",
+ "ll": "≪",
+ "llarr": "⇇",
+ "llcorner": "⌞",
+ "llhard": "⥫",
+ "lltri": "◺",
+ "lmidot": "ŀ",
+ "lmoust": "⎰",
+ "lmoustache": "⎰",
+ "lnE": "≨",
+ "lnap": "⪉",
+ "lnapprox": "⪉",
+ "lne": "⪇",
+ "lneq": "⪇",
+ "lneqq": "≨",
+ "lnsim": "⋦",
+ "loang": "⟬",
+ "loarr": "⇽",
+ "lobrk": "⟦",
+ "longleftarrow": "⟵",
+ "longleftrightarrow": "⟷",
+ "longmapsto": "⟼",
+ "longrightarrow": "⟶",
+ "looparrowleft": "↫",
+ "looparrowright": "↬",
+ "lopar": "⦅",
+ "lopf": "𝕝",
+ "loplus": "⨭",
+ "lotimes": "⨴",
+ "lowast": "∗",
+ "lowbar": "_",
+ "loz": "◊",
+ "lozenge": "◊",
+ "lozf": "⧫",
+ "lpar": "(",
+ "lparlt": "⦓",
+ "lrarr": "⇆",
+ "lrcorner": "⌟",
+ "lrhar": "⇋",
+ "lrhard": "⥭",
+ "lrm": "",
+ "lrtri": "⊿",
+ "lsaquo": "‹",
+ "lscr": "𝓁",
+ "lsh": "↰",
+ "lsim": "≲",
+ "lsime": "⪍",
+ "lsimg": "⪏",
+ "lsqb": "[",
+ "lsquo": "‘",
+ "lsquor": "‚",
+ "lstrok": "ł",
+ "l": "<",
+ "lt": "<",
+ "ltcc": "⪦",
+ "ltcir": "⩹",
+ "ltdot": "⋖",
+ "lthree": "⋋",
+ "ltimes": "⋉",
+ "ltlarr": "⥶",
+ "ltquest": "⩻",
+ "ltrPar": "⦖",
+ "ltri": "◃",
+ "ltrie": "⊴",
+ "ltrif": "◂",
+ "lurdshar": "⥊",
+ "luruhar": "⥦",
+ "lvertneqq": "≨︀",
+ "lvnE": "≨︀",
+ "mDDot": "∺",
+ "mac": "¯",
+ "macr": "¯",
+ "male": "♂",
+ "malt": "✠",
+ "maltese": "✠",
+ "map": "↦",
+ "mapsto": "↦",
+ "mapstodown": "↧",
+ "mapstoleft": "↤",
+ "mapstoup": "↥",
+ "marker": "▮",
+ "mcomma": "⨩",
+ "mcy": "м",
+ "mdash": "—",
+ "measuredangle": "∡",
+ "mfr": "𝔪",
+ "mho": "℧",
+ "micr": "µ",
+ "micro": "µ",
+ "mid": "∣",
+ "midast": "*",
+ "midcir": "⫰",
+ "middo": "·",
+ "middot": "·",
+ "minus": "−",
+ "minusb": "⊟",
+ "minusd": "∸",
+ "minusdu": "⨪",
+ "mlcp": "⫛",
+ "mldr": "…",
+ "mnplus": "∓",
+ "models": "⊧",
+ "mopf": "𝕞",
+ "mp": "∓",
+ "mscr": "𝓂",
+ "mstpos": "∾",
+ "mu": "μ",
+ "multimap": "⊸",
+ "mumap": "⊸",
+ "nGg": "⋙̸",
+ "nGt": "≫⃒",
+ "nGtv": "≫̸",
+ "nLeftarrow": "⇍",
+ "nLeftrightarrow": "⇎",
+ "nLl": "⋘̸",
+ "nLt": "≪⃒",
+ "nLtv": "≪̸",
+ "nRightarrow": "⇏",
+ "nVDash": "⊯",
+ "nVdash": "⊮",
+ "nabla": "∇",
+ "nacute": "ń",
+ "nang": "∠⃒",
+ "nap": "≉",
+ "napE": "⩰̸",
+ "napid": "≋̸",
+ "napos": "ʼn",
+ "napprox": "≉",
+ "natur": "♮",
+ "natural": "♮",
+ "naturals": "ℕ",
+ "nbs": " ",
+ "nbsp": " ",
+ "nbump": "≎̸",
+ "nbumpe": "≏̸",
+ "ncap": "⩃",
+ "ncaron": "ň",
+ "ncedil": "ņ",
+ "ncong": "≇",
+ "ncongdot": "⩭̸",
+ "ncup": "⩂",
+ "ncy": "н",
+ "ndash": "–",
+ "ne": "≠",
+ "neArr": "⇗",
+ "nearhk": "⤤",
+ "nearr": "↗",
+ "nearrow": "↗",
+ "nedot": "≐̸",
+ "nequiv": "≢",
+ "nesear": "⤨",
+ "nesim": "≂̸",
+ "nexist": "∄",
+ "nexists": "∄",
+ "nfr": "𝔫",
+ "ngE": "≧̸",
+ "nge": "≱",
+ "ngeq": "≱",
+ "ngeqq": "≧̸",
+ "ngeqslant": "⩾̸",
+ "nges": "⩾̸",
+ "ngsim": "≵",
+ "ngt": "≯",
+ "ngtr": "≯",
+ "nhArr": "⇎",
+ "nharr": "↮",
+ "nhpar": "⫲",
+ "ni": "∋",
+ "nis": "⋼",
+ "nisd": "⋺",
+ "niv": "∋",
+ "njcy": "њ",
+ "nlArr": "⇍",
+ "nlE": "≦̸",
+ "nlarr": "↚",
+ "nldr": "‥",
+ "nle": "≰",
+ "nleftarrow": "↚",
+ "nleftrightarrow": "↮",
+ "nleq": "≰",
+ "nleqq": "≦̸",
+ "nleqslant": "⩽̸",
+ "nles": "⩽̸",
+ "nless": "≮",
+ "nlsim": "≴",
+ "nlt": "≮",
+ "nltri": "⋪",
+ "nltrie": "⋬",
+ "nmid": "∤",
+ "nopf": "𝕟",
+ "no": "¬",
+ "not": "¬",
+ "notin": "∉",
+ "notinE": "⋹̸",
+ "notindot": "⋵̸",
+ "notinva": "∉",
+ "notinvb": "⋷",
+ "notinvc": "⋶",
+ "notni": "∌",
+ "notniva": "∌",
+ "notnivb": "⋾",
+ "notnivc": "⋽",
+ "npar": "∦",
+ "nparallel": "∦",
+ "nparsl": "⫽⃥",
+ "npart": "∂̸",
+ "npolint": "⨔",
+ "npr": "⊀",
+ "nprcue": "⋠",
+ "npre": "⪯̸",
+ "nprec": "⊀",
+ "npreceq": "⪯̸",
+ "nrArr": "⇏",
+ "nrarr": "↛",
+ "nrarrc": "⤳̸",
+ "nrarrw": "↝̸",
+ "nrightarrow": "↛",
+ "nrtri": "⋫",
+ "nrtrie": "⋭",
+ "nsc": "⊁",
+ "nsccue": "⋡",
+ "nsce": "⪰̸",
+ "nscr": "𝓃",
+ "nshortmid": "∤",
+ "nshortparallel": "∦",
+ "nsim": "≁",
+ "nsime": "≄",
+ "nsimeq": "≄",
+ "nsmid": "∤",
+ "nspar": "∦",
+ "nsqsube": "⋢",
+ "nsqsupe": "⋣",
+ "nsub": "⊄",
+ "nsubE": "⫅̸",
+ "nsube": "⊈",
+ "nsubset": "⊂⃒",
+ "nsubseteq": "⊈",
+ "nsubseteqq": "⫅̸",
+ "nsucc": "⊁",
+ "nsucceq": "⪰̸",
+ "nsup": "⊅",
+ "nsupE": "⫆̸",
+ "nsupe": "⊉",
+ "nsupset": "⊃⃒",
+ "nsupseteq": "⊉",
+ "nsupseteqq": "⫆̸",
+ "ntgl": "≹",
+ "ntild": "ñ",
+ "ntilde": "ñ",
+ "ntlg": "≸",
+ "ntriangleleft": "⋪",
+ "ntrianglelefteq": "⋬",
+ "ntriangleright": "⋫",
+ "ntrianglerighteq": "⋭",
+ "nu": "ν",
+ "num": "#",
+ "numero": "№",
+ "numsp": " ",
+ "nvDash": "⊭",
+ "nvHarr": "⤄",
+ "nvap": "≍⃒",
+ "nvdash": "⊬",
+ "nvge": "≥⃒",
+ "nvgt": ">⃒",
+ "nvinfin": "⧞",
+ "nvlArr": "⤂",
+ "nvle": "≤⃒",
+ "nvlt": "<⃒",
+ "nvltrie": "⊴⃒",
+ "nvrArr": "⤃",
+ "nvrtrie": "⊵⃒",
+ "nvsim": "∼⃒",
+ "nwArr": "⇖",
+ "nwarhk": "⤣",
+ "nwarr": "↖",
+ "nwarrow": "↖",
+ "nwnear": "⤧",
+ "oS": "Ⓢ",
+ "oacut": "ó",
+ "oacute": "ó",
+ "oast": "⊛",
+ "ocir": "ô",
+ "ocirc": "ô",
+ "ocy": "о",
+ "odash": "⊝",
+ "odblac": "ő",
+ "odiv": "⨸",
+ "odot": "⊙",
+ "odsold": "⦼",
+ "oelig": "œ",
+ "ofcir": "⦿",
+ "ofr": "𝔬",
+ "ogon": "˛",
+ "ograv": "ò",
+ "ograve": "ò",
+ "ogt": "⧁",
+ "ohbar": "⦵",
+ "ohm": "Ω",
+ "oint": "∮",
+ "olarr": "↺",
+ "olcir": "⦾",
+ "olcross": "⦻",
+ "oline": "‾",
+ "olt": "⧀",
+ "omacr": "ō",
+ "omega": "ω",
+ "omicron": "ο",
+ "omid": "⦶",
+ "ominus": "⊖",
+ "oopf": "𝕠",
+ "opar": "⦷",
+ "operp": "⦹",
+ "oplus": "⊕",
+ "or": "∨",
+ "orarr": "↻",
+ "ord": "º",
+ "order": "ℴ",
+ "orderof": "ℴ",
+ "ordf": "ª",
+ "ordm": "º",
+ "origof": "⊶",
+ "oror": "⩖",
+ "orslope": "⩗",
+ "orv": "⩛",
+ "oscr": "ℴ",
+ "oslas": "ø",
+ "oslash": "ø",
+ "osol": "⊘",
+ "otild": "õ",
+ "otilde": "õ",
+ "otimes": "⊗",
+ "otimesas": "⨶",
+ "oum": "ö",
+ "ouml": "ö",
+ "ovbar": "⌽",
+ "par": "¶",
+ "para": "¶",
+ "parallel": "∥",
+ "parsim": "⫳",
+ "parsl": "⫽",
+ "part": "∂",
+ "pcy": "п",
+ "percnt": "%",
+ "period": ".",
+ "permil": "‰",
+ "perp": "⊥",
+ "pertenk": "‱",
+ "pfr": "𝔭",
+ "phi": "φ",
+ "phiv": "ϕ",
+ "phmmat": "ℳ",
+ "phone": "☎",
+ "pi": "π",
+ "pitchfork": "⋔",
+ "piv": "ϖ",
+ "planck": "ℏ",
+ "planckh": "ℎ",
+ "plankv": "ℏ",
+ "plus": "+",
+ "plusacir": "⨣",
+ "plusb": "⊞",
+ "pluscir": "⨢",
+ "plusdo": "∔",
+ "plusdu": "⨥",
+ "pluse": "⩲",
+ "plusm": "±",
+ "plusmn": "±",
+ "plussim": "⨦",
+ "plustwo": "⨧",
+ "pm": "±",
+ "pointint": "⨕",
+ "popf": "𝕡",
+ "poun": "£",
+ "pound": "£",
+ "pr": "≺",
+ "prE": "⪳",
+ "prap": "⪷",
+ "prcue": "≼",
+ "pre": "⪯",
+ "prec": "≺",
+ "precapprox": "⪷",
+ "preccurlyeq": "≼",
+ "preceq": "⪯",
+ "precnapprox": "⪹",
+ "precneqq": "⪵",
+ "precnsim": "⋨",
+ "precsim": "≾",
+ "prime": "′",
+ "primes": "ℙ",
+ "prnE": "⪵",
+ "prnap": "⪹",
+ "prnsim": "⋨",
+ "prod": "∏",
+ "profalar": "⌮",
+ "profline": "⌒",
+ "profsurf": "⌓",
+ "prop": "∝",
+ "propto": "∝",
+ "prsim": "≾",
+ "prurel": "⊰",
+ "pscr": "𝓅",
+ "psi": "ψ",
+ "puncsp": " ",
+ "qfr": "𝔮",
+ "qint": "⨌",
+ "qopf": "𝕢",
+ "qprime": "⁗",
+ "qscr": "𝓆",
+ "quaternions": "ℍ",
+ "quatint": "⨖",
+ "quest": "?",
+ "questeq": "≟",
+ "quo": "\"",
+ "quot": "\"",
+ "rAarr": "⇛",
+ "rArr": "⇒",
+ "rAtail": "⤜",
+ "rBarr": "⤏",
+ "rHar": "⥤",
+ "race": "∽̱",
+ "racute": "ŕ",
+ "radic": "√",
+ "raemptyv": "⦳",
+ "rang": "⟩",
+ "rangd": "⦒",
+ "range": "⦥",
+ "rangle": "⟩",
+ "raqu": "»",
+ "raquo": "»",
+ "rarr": "→",
+ "rarrap": "⥵",
+ "rarrb": "⇥",
+ "rarrbfs": "⤠",
+ "rarrc": "⤳",
+ "rarrfs": "⤞",
+ "rarrhk": "↪",
+ "rarrlp": "↬",
+ "rarrpl": "⥅",
+ "rarrsim": "⥴",
+ "rarrtl": "↣",
+ "rarrw": "↝",
+ "ratail": "⤚",
+ "ratio": "∶",
+ "rationals": "ℚ",
+ "rbarr": "⤍",
+ "rbbrk": "❳",
+ "rbrace": "}",
+ "rbrack": "]",
+ "rbrke": "⦌",
+ "rbrksld": "⦎",
+ "rbrkslu": "⦐",
+ "rcaron": "ř",
+ "rcedil": "ŗ",
+ "rceil": "⌉",
+ "rcub": "}",
+ "rcy": "р",
+ "rdca": "⤷",
+ "rdldhar": "⥩",
+ "rdquo": "”",
+ "rdquor": "”",
+ "rdsh": "↳",
+ "real": "ℜ",
+ "realine": "ℛ",
+ "realpart": "ℜ",
+ "reals": "ℝ",
+ "rect": "▭",
+ "re": "®",
+ "reg": "®",
+ "rfisht": "⥽",
+ "rfloor": "⌋",
+ "rfr": "𝔯",
+ "rhard": "⇁",
+ "rharu": "⇀",
+ "rharul": "⥬",
+ "rho": "ρ",
+ "rhov": "ϱ",
+ "rightarrow": "→",
+ "rightarrowtail": "↣",
+ "rightharpoondown": "⇁",
+ "rightharpoonup": "⇀",
+ "rightleftarrows": "⇄",
+ "rightleftharpoons": "⇌",
+ "rightrightarrows": "⇉",
+ "rightsquigarrow": "↝",
+ "rightthreetimes": "⋌",
+ "ring": "˚",
+ "risingdotseq": "≓",
+ "rlarr": "⇄",
+ "rlhar": "⇌",
+ "rlm": "",
+ "rmoust": "⎱",
+ "rmoustache": "⎱",
+ "rnmid": "⫮",
+ "roang": "⟭",
+ "roarr": "⇾",
+ "robrk": "⟧",
+ "ropar": "⦆",
+ "ropf": "𝕣",
+ "roplus": "⨮",
+ "rotimes": "⨵",
+ "rpar": ")",
+ "rpargt": "⦔",
+ "rppolint": "⨒",
+ "rrarr": "⇉",
+ "rsaquo": "›",
+ "rscr": "𝓇",
+ "rsh": "↱",
+ "rsqb": "]",
+ "rsquo": "’",
+ "rsquor": "’",
+ "rthree": "⋌",
+ "rtimes": "⋊",
+ "rtri": "▹",
+ "rtrie": "⊵",
+ "rtrif": "▸",
+ "rtriltri": "⧎",
+ "ruluhar": "⥨",
+ "rx": "℞",
+ "sacute": "ś",
+ "sbquo": "‚",
+ "sc": "≻",
+ "scE": "⪴",
+ "scap": "⪸",
+ "scaron": "š",
+ "sccue": "≽",
+ "sce": "⪰",
+ "scedil": "ş",
+ "scirc": "ŝ",
+ "scnE": "⪶",
+ "scnap": "⪺",
+ "scnsim": "⋩",
+ "scpolint": "⨓",
+ "scsim": "≿",
+ "scy": "с",
+ "sdot": "⋅",
+ "sdotb": "⊡",
+ "sdote": "⩦",
+ "seArr": "⇘",
+ "searhk": "⤥",
+ "searr": "↘",
+ "searrow": "↘",
+ "sec": "§",
+ "sect": "§",
+ "semi": ";",
+ "seswar": "⤩",
+ "setminus": "∖",
+ "setmn": "∖",
+ "sext": "✶",
+ "sfr": "𝔰",
+ "sfrown": "⌢",
+ "sharp": "♯",
+ "shchcy": "щ",
+ "shcy": "ш",
+ "shortmid": "∣",
+ "shortparallel": "∥",
+ "sh": "",
+ "shy": "",
+ "sigma": "σ",
+ "sigmaf": "ς",
+ "sigmav": "ς",
+ "sim": "∼",
+ "simdot": "⩪",
+ "sime": "≃",
+ "simeq": "≃",
+ "simg": "⪞",
+ "simgE": "⪠",
+ "siml": "⪝",
+ "simlE": "⪟",
+ "simne": "≆",
+ "simplus": "⨤",
+ "simrarr": "⥲",
+ "slarr": "←",
+ "smallsetminus": "∖",
+ "smashp": "⨳",
+ "smeparsl": "⧤",
+ "smid": "∣",
+ "smile": "⌣",
+ "smt": "⪪",
+ "smte": "⪬",
+ "smtes": "⪬︀",
+ "softcy": "ь",
+ "sol": "/",
+ "solb": "⧄",
+ "solbar": "⌿",
+ "sopf": "𝕤",
+ "spades": "♠",
+ "spadesuit": "♠",
+ "spar": "∥",
+ "sqcap": "⊓",
+ "sqcaps": "⊓︀",
+ "sqcup": "⊔",
+ "sqcups": "⊔︀",
+ "sqsub": "⊏",
+ "sqsube": "⊑",
+ "sqsubset": "⊏",
+ "sqsubseteq": "⊑",
+ "sqsup": "⊐",
+ "sqsupe": "⊒",
+ "sqsupset": "⊐",
+ "sqsupseteq": "⊒",
+ "squ": "□",
+ "square": "□",
+ "squarf": "▪",
+ "squf": "▪",
+ "srarr": "→",
+ "sscr": "𝓈",
+ "ssetmn": "∖",
+ "ssmile": "⌣",
+ "sstarf": "⋆",
+ "star": "☆",
+ "starf": "★",
+ "straightepsilon": "ϵ",
+ "straightphi": "ϕ",
+ "strns": "¯",
+ "sub": "⊂",
+ "subE": "⫅",
+ "subdot": "⪽",
+ "sube": "⊆",
+ "subedot": "⫃",
+ "submult": "⫁",
+ "subnE": "⫋",
+ "subne": "⊊",
+ "subplus": "⪿",
+ "subrarr": "⥹",
+ "subset": "⊂",
+ "subseteq": "⊆",
+ "subseteqq": "⫅",
+ "subsetneq": "⊊",
+ "subsetneqq": "⫋",
+ "subsim": "⫇",
+ "subsub": "⫕",
+ "subsup": "⫓",
+ "succ": "≻",
+ "succapprox": "⪸",
+ "succcurlyeq": "≽",
+ "succeq": "⪰",
+ "succnapprox": "⪺",
+ "succneqq": "⪶",
+ "succnsim": "⋩",
+ "succsim": "≿",
+ "sum": "∑",
+ "sung": "♪",
+ "sup": "⊃",
+ "sup1": "¹",
+ "sup2": "²",
+ "sup3": "³",
+ "supE": "⫆",
+ "supdot": "⪾",
+ "supdsub": "⫘",
+ "supe": "⊇",
+ "supedot": "⫄",
+ "suphsol": "⟉",
+ "suphsub": "⫗",
+ "suplarr": "⥻",
+ "supmult": "⫂",
+ "supnE": "⫌",
+ "supne": "⊋",
+ "supplus": "⫀",
+ "supset": "⊃",
+ "supseteq": "⊇",
+ "supseteqq": "⫆",
+ "supsetneq": "⊋",
+ "supsetneqq": "⫌",
+ "supsim": "⫈",
+ "supsub": "⫔",
+ "supsup": "⫖",
+ "swArr": "⇙",
+ "swarhk": "⤦",
+ "swarr": "↙",
+ "swarrow": "↙",
+ "swnwar": "⤪",
+ "szli": "ß",
+ "szlig": "ß",
+ "target": "⌖",
+ "tau": "τ",
+ "tbrk": "⎴",
+ "tcaron": "ť",
+ "tcedil": "ţ",
+ "tcy": "т",
+ "tdot": "⃛",
+ "telrec": "⌕",
+ "tfr": "𝔱",
+ "there4": "∴",
+ "therefore": "∴",
+ "theta": "θ",
+ "thetasym": "ϑ",
+ "thetav": "ϑ",
+ "thickapprox": "≈",
+ "thicksim": "∼",
+ "thinsp": " ",
+ "thkap": "≈",
+ "thksim": "∼",
+ "thor": "þ",
+ "thorn": "þ",
+ "tilde": "˜",
+ "time": "×",
+ "times": "×",
+ "timesb": "⊠",
+ "timesbar": "⨱",
+ "timesd": "⨰",
+ "tint": "∭",
+ "toea": "⤨",
+ "top": "⊤",
+ "topbot": "⌶",
+ "topcir": "⫱",
+ "topf": "𝕥",
+ "topfork": "⫚",
+ "tosa": "⤩",
+ "tprime": "‴",
+ "trade": "™",
+ "triangle": "▵",
+ "triangledown": "▿",
+ "triangleleft": "◃",
+ "trianglelefteq": "⊴",
+ "triangleq": "≜",
+ "triangleright": "▹",
+ "trianglerighteq": "⊵",
+ "tridot": "◬",
+ "trie": "≜",
+ "triminus": "⨺",
+ "triplus": "⨹",
+ "trisb": "⧍",
+ "tritime": "⨻",
+ "trpezium": "⏢",
+ "tscr": "𝓉",
+ "tscy": "ц",
+ "tshcy": "ћ",
+ "tstrok": "ŧ",
+ "twixt": "≬",
+ "twoheadleftarrow": "↞",
+ "twoheadrightarrow": "↠",
+ "uArr": "⇑",
+ "uHar": "⥣",
+ "uacut": "ú",
+ "uacute": "ú",
+ "uarr": "↑",
+ "ubrcy": "ў",
+ "ubreve": "ŭ",
+ "ucir": "û",
+ "ucirc": "û",
+ "ucy": "у",
+ "udarr": "⇅",
+ "udblac": "ű",
+ "udhar": "⥮",
+ "ufisht": "⥾",
+ "ufr": "𝔲",
+ "ugrav": "ù",
+ "ugrave": "ù",
+ "uharl": "↿",
+ "uharr": "↾",
+ "uhblk": "▀",
+ "ulcorn": "⌜",
+ "ulcorner": "⌜",
+ "ulcrop": "⌏",
+ "ultri": "◸",
+ "umacr": "ū",
+ "um": "¨",
+ "uml": "¨",
+ "uogon": "ų",
+ "uopf": "𝕦",
+ "uparrow": "↑",
+ "updownarrow": "↕",
+ "upharpoonleft": "↿",
+ "upharpoonright": "↾",
+ "uplus": "⊎",
+ "upsi": "υ",
+ "upsih": "ϒ",
+ "upsilon": "υ",
+ "upuparrows": "⇈",
+ "urcorn": "⌝",
+ "urcorner": "⌝",
+ "urcrop": "⌎",
+ "uring": "ů",
+ "urtri": "◹",
+ "uscr": "𝓊",
+ "utdot": "⋰",
+ "utilde": "ũ",
+ "utri": "▵",
+ "utrif": "▴",
+ "uuarr": "⇈",
+ "uum": "ü",
+ "uuml": "ü",
+ "uwangle": "⦧",
+ "vArr": "⇕",
+ "vBar": "⫨",
+ "vBarv": "⫩",
+ "vDash": "⊨",
+ "vangrt": "⦜",
+ "varepsilon": "ϵ",
+ "varkappa": "ϰ",
+ "varnothing": "∅",
+ "varphi": "ϕ",
+ "varpi": "ϖ",
+ "varpropto": "∝",
+ "varr": "↕",
+ "varrho": "ϱ",
+ "varsigma": "ς",
+ "varsubsetneq": "⊊︀",
+ "varsubsetneqq": "⫋︀",
+ "varsupsetneq": "⊋︀",
+ "varsupsetneqq": "⫌︀",
+ "vartheta": "ϑ",
+ "vartriangleleft": "⊲",
+ "vartriangleright": "⊳",
+ "vcy": "в",
+ "vdash": "⊢",
+ "vee": "∨",
+ "veebar": "⊻",
+ "veeeq": "≚",
+ "vellip": "⋮",
+ "verbar": "|",
+ "vert": "|",
+ "vfr": "𝔳",
+ "vltri": "⊲",
+ "vnsub": "⊂⃒",
+ "vnsup": "⊃⃒",
+ "vopf": "𝕧",
+ "vprop": "∝",
+ "vrtri": "⊳",
+ "vscr": "𝓋",
+ "vsubnE": "⫋︀",
+ "vsubne": "⊊︀",
+ "vsupnE": "⫌︀",
+ "vsupne": "⊋︀",
+ "vzigzag": "⦚",
+ "wcirc": "ŵ",
+ "wedbar": "⩟",
+ "wedge": "∧",
+ "wedgeq": "≙",
+ "weierp": "℘",
+ "wfr": "𝔴",
+ "wopf": "𝕨",
+ "wp": "℘",
+ "wr": "≀",
+ "wreath": "≀",
+ "wscr": "𝓌",
+ "xcap": "⋂",
+ "xcirc": "◯",
+ "xcup": "⋃",
+ "xdtri": "▽",
+ "xfr": "𝔵",
+ "xhArr": "⟺",
+ "xharr": "⟷",
+ "xi": "ξ",
+ "xlArr": "⟸",
+ "xlarr": "⟵",
+ "xmap": "⟼",
+ "xnis": "⋻",
+ "xodot": "⨀",
+ "xopf": "𝕩",
+ "xoplus": "⨁",
+ "xotime": "⨂",
+ "xrArr": "⟹",
+ "xrarr": "⟶",
+ "xscr": "𝓍",
+ "xsqcup": "⨆",
+ "xuplus": "⨄",
+ "xutri": "△",
+ "xvee": "⋁",
+ "xwedge": "⋀",
+ "yacut": "ý",
+ "yacute": "ý",
+ "yacy": "я",
+ "ycirc": "ŷ",
+ "ycy": "ы",
+ "ye": "¥",
+ "yen": "¥",
+ "yfr": "𝔶",
+ "yicy": "ї",
+ "yopf": "𝕪",
+ "yscr": "𝓎",
+ "yucy": "ю",
+ "yum": "ÿ",
+ "yuml": "ÿ",
+ "zacute": "ź",
+ "zcaron": "ž",
+ "zcy": "з",
+ "zdot": "ż",
+ "zeetrf": "ℨ",
+ "zeta": "ζ",
+ "zfr": "𝔷",
+ "zhcy": "ж",
+ "zigrarr": "⇝",
+ "zopf": "𝕫",
+ "zscr": "𝓏",
+ "zwj": "",
+ "zwnj": ""
+};
+
+/***/ },
+/* 890 */
+/***/ function(module, exports) {
+
+module.exports = {
+ "0": "�",
+ "128": "€",
+ "130": "‚",
+ "131": "ƒ",
+ "132": "„",
+ "133": "…",
+ "134": "†",
+ "135": "‡",
+ "136": "ˆ",
+ "137": "‰",
+ "138": "Š",
+ "139": "‹",
+ "140": "Œ",
+ "142": "Ž",
+ "145": "‘",
+ "146": "’",
+ "147": "“",
+ "148": "”",
+ "149": "•",
+ "150": "–",
+ "151": "—",
+ "152": "˜",
+ "153": "™",
+ "154": "š",
+ "155": "›",
+ "156": "œ",
+ "158": "ž",
+ "159": "Ÿ"
+};
+
+/***/ },
+/* 891 */
+/***/ function(module, exports) {
+
+module.exports = [
+ "article",
+ "header",
+ "aside",
+ "hgroup",
+ "blockquote",
+ "hr",
+ "iframe",
+ "body",
+ "li",
+ "map",
+ "button",
+ "object",
+ "canvas",
+ "ol",
+ "caption",
+ "output",
+ "col",
+ "p",
+ "colgroup",
+ "pre",
+ "dd",
+ "progress",
+ "div",
+ "section",
+ "dl",
+ "table",
+ "td",
+ "dt",
+ "tbody",
+ "embed",
+ "textarea",
+ "fieldset",
+ "tfoot",
+ "figcaption",
+ "th",
+ "figure",
+ "thead",
+ "footer",
+ "tr",
+ "form",
+ "ul",
+ "h1",
+ "h2",
+ "h3",
+ "h4",
+ "h5",
+ "h6",
+ "video",
+ "script",
+ "style"
+];
+
+/***/ },
+/* 892 */
+/***/ function(module, exports, __webpack_require__) {
+
+"use strict";
+'use strict';var _react=__webpack_require__(0);var _react2=_interopRequireDefault(_react);var _reactDom=__webpack_require__(215);var _reactDom2=_interopRequireDefault(_reactDom);var _redux=__webpack_require__(216);var Redux=_interopRequireWildcard(_redux);var _reactRedux=__webpack_require__(52);var _createBrowserHistory=__webpack_require__(430);var _createBrowserHistory2=_interopRequireDefault(_createBrowserHistory);var _reactRouter=__webpack_require__(63);var _localStore=__webpack_require__(431);var localStore=_interopRequireWildcard(_localStore);var _reducers=__webpack_require__(217);var reducers=_interopRequireWildcard(_reducers);var _routes=__webpack_require__(432);var _routes2=_interopRequireDefault(_routes);var _actions=__webpack_require__(80);var Actions=_interopRequireWildcard(_actions);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}//the localStore implementation is naive
//initial state should be rehydrated from the server
//then additional state transformations should be applied based on localStore contents
// (or not? maybe localStore is not needed)
var initialState=window.__INITIAL_STATE__;//create the redux store
//initial state is retrieved from localStore
-var store=__WEBPACK_IMPORTED_MODULE_2_redux__["createStore"](__WEBPACK_IMPORTED_MODULE_2_redux__["combineReducers"](__WEBPACK_IMPORTED_MODULE_7__common_reducers__),initialState,window.devToolsExtension?window.devToolsExtension():undefined);var localInput=__WEBPACK_IMPORTED_MODULE_6__common_localStore__["a" /* get */]('dubdiff');if(localInput.input){}//dispatch localStore data to store
-//should this be done after the first render?
-//save the state whenever the state changes
+var store=Redux.createStore(Redux.combineReducers(reducers),initialState,window.devToolsExtension?window.devToolsExtension():undefined);var localInput=localStore.get('dubdiff');console.log(localInput);if(localInput.input){//dispatch localStore data to store
+store.dispatch(Actions.updateOriginalInput(localInput.input.original));store.dispatch(Actions.updateFinalInput(localInput.input.final));//should this be done after the first render?
+}//save the state whenever the state changes
function saveState(){var state=store.getState();//pass the elements of state that should be persisted to the local store as an array of element name strings
-__WEBPACK_IMPORTED_MODULE_6__common_localStore__["b" /* set */](state,["input"],"dubdiff");}store.subscribe(saveState);function render(){__WEBPACK_IMPORTED_MODULE_1_react_dom___default.a.render(__WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement(__WEBPACK_IMPORTED_MODULE_3_react_redux__["Provider"],{store:store},__WEBPACK_IMPORTED_MODULE_0_react___default.a.createElement(__WEBPACK_IMPORTED_MODULE_5_react_router__["Router"],{history:__WEBPACK_IMPORTED_MODULE_4_history_lib_createBrowserHistory___default()()},__WEBPACK_IMPORTED_MODULE_8__common_routes__["a" /* default */])),document.getElementById('root'));}render();
+localStore.set(state,["input"],"dubdiff");}store.subscribe(saveState);function render(){_reactDom2.default.render(_react2.default.createElement(_reactRedux.Provider,{store:store},_react2.default.createElement(_reactRouter.Router,{history:(0,_createBrowserHistory2.default)()},_routes2.default)),document.getElementById('root'));}render();
/***/ }
/******/ ]);
\ No newline at end of file
diff --git a/package.json b/package.json
index 941fc75..9fedbcf 100644
--- a/package.json
+++ b/package.json
@@ -10,18 +10,19 @@
"serve": "node src/server/babel.index.js",
"webpack-stats": "webpack --profile --json > stats.json",
"test": "mocha --watch --compilers js:babel-register"
-
},
"author": "",
"license": "BSD-2-Clause",
"dependencies": {
"babel-preset-es2015-mod": "^6.6.0",
"babel-preset-es3": "^1.0.1",
+ "babel-preset-stage-2": "^6.18.0",
"body-parser": "^1.15.2",
"diff": "^3.0.1",
"express": "^4.14.0",
"jsonfile": "^2.4.0",
"markdown-it": "^5.1.0",
+ "markdown-to-jsx": "^4.0.3",
"react": "^0.14.5",
"react-dom": "^0.14.5",
"react-redux": "^4.4.6",
@@ -43,6 +44,7 @@
"babel-register": "^6.18.0",
"chai": "^3.5.0",
"copyfiles": "^0.2.2",
+ "json-loader": "^0.5.4",
"mocha": "^3.2.0",
"piping": "^1.0.0-rc.4",
"webpack": "^2.1.0-beta.27"
diff --git a/src/client/index.js b/src/client/index.js
index 0f578df..c4b7044 100644
--- a/src/client/index.js
+++ b/src/client/index.js
@@ -11,6 +11,8 @@ import {Router, Route, IndexRoute, Redirect } from 'react-router'
import * as localStore from '../common/localStore'
import * as reducers from '../common/reducers'
import routes from '../common/routes'
+import * as Actions from '../common/actions'
+
//the localStore implementation is naive
@@ -29,8 +31,11 @@ const store = Redux.createStore(
)
const localInput = localStore.get('dubdiff')
+console.log(localInput)
if (localInput.input) {
//dispatch localStore data to store
+ store.dispatch(Actions.updateOriginalInput(localInput.input.original))
+ store.dispatch(Actions.updateFinalInput(localInput.input.final))
//should this be done after the first render?
}
diff --git a/src/common/components/Compare.js b/src/common/components/Compare.js
index 4d869b8..25d65d8 100644
--- a/src/common/components/Compare.js
+++ b/src/common/components/Compare.js
@@ -11,24 +11,26 @@ import Footer from './Footer'
import CompareControls from './CompareControls'
import ShowPlaintext from './ShowPlaintext'
+import ShowMarkdown from './ShowMarkdown'
const mapStateToProps = (state) => ({
isMarkdownFormat: Selectors.isMarkdownFormat(state),
- isShowOriginal: Selectors.isShowOriginal(state),
+ isShowOriginal: Selectors.isShowOriginal(state),
isShowFinal: Selectors.isShowFinal(state),
isShowDifference: Selectors.isShowDifference(state),
- compare: state.compare,
+ compare: state.compare,
diff: Selectors.diff(state)
})
const mapDispatchToProps = dispatch => ({
})
-
+
class Compare extends React.Component {
render() {
+ console.log({isMarkdownFormat: this.props.isMarkdownFormat, isShowDifference: this.props.isShowDifference})
return (
@@ -40,14 +42,20 @@ class Compare extends React.Component {
- { this.props.isShowDifference ?
-
- {this.props.diff}:
-
-
+ {
+ (!this.props.isMarkdownFormat && this.props.isShowDifference) ?
+ {this.props.diff}:
+ (this.props.isMarkdownFormat && this.props.isShowDifference) ?
+ {this.props.diff}:
+ (!this.props.isMarkdownFormat && !this.props.isShowDifference) ?
+ :
+ (this.props.isMarkdownFormat && !this.props.isShowDifference) ?
+ :
+ null
}
diff --git a/src/common/components/ShowMarkdown.js b/src/common/components/ShowMarkdown.js
index 29a2196..c99e588 100644
--- a/src/common/components/ShowMarkdown.js
+++ b/src/common/components/ShowMarkdown.js
@@ -1,34 +1,23 @@
import React from 'react'
+import markdownCompiler from 'markdown-to-jsx'
-//use markdown-it to render markdown
-//alternately use markdown to jsx
+import {diffToString, diffToHtml} from '../util/dubdiff'
const ShowMarkdown = (props) => {
+ if (props.diff)
+ console.log(diffToString(props.diff))
+
return
-
- {props.text ?
- props.text:
+ {
+ props.text ?
+ markdownCompiler(props.text) :
props.diff ?
- diffToPre(props.diff) :
- null
+ markdownCompiler(diffToHtml(props.diff)) :
+ null
}
-
}
export default ShowMarkdown
-function diffToPre(diff) {
- return diff.map(part => (
- part.added ?
{part.value}{ifNotNewlineSpace(part.value)} :
- part.removed ?
{part.value}{ifNotNewlineSpace(part.value)} :
-
{part.value}{ifNotNewlineSpace(part.value)}
- ))
-}
-
-
-
-const ifNotNewlineSpace = str => {
- return !str.endsWith('\n') ? ' ' : ''
-}
\ No newline at end of file
diff --git a/src/common/components/ShowPlaintext.js b/src/common/components/ShowPlaintext.js
index c790fef..3c74860 100644
--- a/src/common/components/ShowPlaintext.js
+++ b/src/common/components/ShowPlaintext.js
@@ -8,7 +8,7 @@ const ShowPlaintext = (props) => {
props.text:
props.diff ?
diffToPre(props.diff) :
- null
+ null
}
@@ -18,14 +18,8 @@ export default ShowPlaintext
function diffToPre(diff) {
return diff.map((part, index) => (
- part.added ? {part.value}{ifNotNewlineSpace(part.value)} :
- part.removed ? {part.value}{ifNotNewlineSpace(part.value)} :
- {part.value}{ifNotNewlineSpace(part.value)}
+ part.added ? {part.value} :
+ part.removed ? {part.value} :
+ {part.value}
))
}
-
-
-
-const ifNotNewlineSpace = str => {
- return !str.endsWith('\n') ? ' ' : ''
-}
\ No newline at end of file
diff --git a/src/common/util/EditorsDiff.js b/src/common/util/EditorsDiff.js
index 9ec5d2b..bdd7aec 100644
--- a/src/common/util/EditorsDiff.js
+++ b/src/common/util/EditorsDiff.js
@@ -1,44 +1,62 @@
import {Diff} from 'diff'
-const EditorsDiff = new Diff()
+// EditorsDiff is a custom Diff implementation from the jsdiff library
+// It allows diffing by phrases. Whitespace is ignored for the purpose of comparison,
+// but is preserved and included in the output.
-EditorsDiff.equals = function(left, right) {
- return (
- left.string == right.string
- )
+const TOKEN_BOUNDARYS = /([\s,.:])/
-}
-EditorsDiff.tokenize = function(value) {
- let tokens = value.split(/([ ]+)|(\n)/)
- let annotatedTokens = []
- tokens.forEach( token => {
- if (isSpace(token)) {
- if (annotatedTokens.length == 0)
- annotatedTokens.push({string:'', whitespace:[]})
+class EditorsDiff extends Diff {
+ constructor (tokenBoundaries=TOKEN_BOUNDARYS) {
+ super()
+ this.tokenBoundaries = tokenBoundaries
+ }
- let last = annotatedTokens[annotatedTokens.length-1]
- last.whitespace.push(token)
- }
- else {
- annotatedTokens.push({string:token, whitespace:[]})
- }
- })
- console.log(annotatedTokens)
- return annotatedTokens
-}
-EditorsDiff.join = function (annotatedTokens) {
- let tokens = []
- annotatedTokens.forEach(annotatedToken => {
- tokens.push(annotatedToken.string)
- annotatedToken.whitespace.forEach(item => {
- tokens.push(item)
+ equals (left, right) {
+ return (
+ left.string == right.string
+ )
+
+ }
+
+
+ //splits the input string into a series of word and punctuation tokens
+ //each token is associated with an optional trailing array of spaces
+ tokenize (value) {
+ let tokens = value.split(this.tokenBoundaries)
+ let annotatedTokens = []
+ tokens.forEach( token => {
+ if (isSpace(token)) {
+ if (annotatedTokens.length == 0)
+ annotatedTokens.push({string:'', whitespace:[]})
+
+ let last = annotatedTokens[annotatedTokens.length-1]
+ last.whitespace.push(token)
+ }
+ else {
+ annotatedTokens.push({string:token, whitespace:[]})
+ }
})
- })
- console.log(tokens.join(''))
- return tokens.join('')
-}
+ //this final empty token is necessary for the jsdiff diffing engine to work properly
+ annotatedTokens.push({string:'', whitespace:[]})
+ return annotatedTokens
+ }
+ join(annotatedTokens) {
+ let tokens = []
+ annotatedTokens.forEach(annotatedToken => {
+ tokens.push(annotatedToken.string)
+ annotatedToken.whitespace.forEach(item => {
+ tokens.push(item)
+ })
+ })
+ return tokens.join('')
+ }
+}
+
+
+
export default EditorsDiff
diff --git a/src/common/util/dubdiff.js b/src/common/util/dubdiff.js
index 806d1fc..fe5bba9 100644
--- a/src/common/util/dubdiff.js
+++ b/src/common/util/dubdiff.js
@@ -1,32 +1,18 @@
import * as JsDiff from 'diff'
import EditorsDiff from './EditorsDiff'
+let plaintextDiffer = new EditorsDiff()
+let markdownDiffer = new EditorsDiff(/([\s,.:]|[*\[\]\(\)])/)
-//!!! this deal with adding and removing spaces could be done more elegantly by
-// diffing on an array of simple data structures that contain the text and the adjacent space
-// the diff would use a custom compare function that would disregard the spaces
-// alternately, the text could be split with the spaces included in the array and then compared with a
-// custom diff function that would treat the space elements as null/ignored
-
-//the current mechanism for adding and removing spaces is fragile and broken
+//returns a comparison of the texts as plaintext
export function plaintextDiff(original, final) {
- //let arrOriginal = plaintextSplit(original)
- //let arrFinal = plaintextSplit(final)
-
- let diff = EditorsDiff.diff(original, final)
- //diff = plaintextRestoreSpaces(diff)
-
+ let diff = plaintextDiffer.diff(original, final)
return diff
}
+//returns a comparison of the texts as markdown
export function markdownDiff(original, final) {
-// let arrOriginal = plaintextSplit(original)
-// let arrFinal = plaintextSplit(final)
-
-// let diff = JsDiff.diffArrays(arrOriginal, arrFinal)
-// diff = plaintextRestoreSpaces(diff)
-
- let diff = EditorsDiff.diff(original, final)
+ let diff = markdownDiffer.diff(original, final)
diff = rewriteMarkdownDiff(diff)
return diff
@@ -34,10 +20,12 @@ export function markdownDiff(original, final) {
// returns a string version of the diff, with "{+ ... +}" and "[- ... -]"
// representing ins and del blocks
-export function diffToString(diff) {
+export function diffToString(diff, tags={added:{start:'{+', end:'+}'}, removed:{start:'[-', end:'-]'}, same:{start:'', end:''}}) {
+
return diff.map(({added, removed, value}) => {
- let start = added ? '{+' : removed ? '[-' : ''
- let end = added ? '+}' : removed ? '-]' : ''
+
+ let {start,end} = added ? tags.added : (removed ? tags.removed : tags.same)
+
let string = value
if (Array.isArray(value))
string = value.join('')
@@ -46,16 +34,8 @@ export function diffToString(diff) {
}).join('')
}
-let plaintextSplit = text =>text.split(/[ ]|(\n)/)
-
-function plaintextRestoreSpaces (diff) {
- return diff.map(({added, removed, value}) => ({
- added,
- removed,
- value:value.map((str, idx, arr) => (
- (str!='\n' && (idx', end:''}, removed:{start:'', end:''}, same:{start:'', end:''}})
}
@@ -80,7 +60,7 @@ function rewriteMarkdownDiff(diff) {
//apply transformation rules
let transformedDiff = diff
transformedDiff= applyTransformationRule1(transformedDiff)
- //transformedDiff= applyTransformationRule2(transformedDiff)
+ transformedDiff= applyTransformationRule2(transformedDiff)
return transformedDiff
}
@@ -109,7 +89,6 @@ function applyTransformationRule1(diff) {
// the previous block was a del and had multiple lines
// the current block is an ins
if (previousBlockType == B_REMOVED && currentBlockType == B_ADDED && previousBlockWasMultiline) {
- console.log('trigger rule 1')
//split the first line from the current block
let currentBlockSplit = splitMultilineDiffBlock(currentBlock)
@@ -120,7 +99,6 @@ function applyTransformationRule1(diff) {
//split the first line from the previous block
let previousBlockSplit = splitMultilineDiffBlock(previousBlock)
- console.log({currentBlock, currentBlockSplit, previousBlock, previousBlockSplit})
//now add the blocks back, interleaving del and ins blocks
for (let i=0; i)* - blockquotes (possibly nested)
+ // (
+ // ([ \t]*#*) - headers
+ // |([ \t]+[\*\+-]) - unordered lists
+ // |([ \t]+[0-9]+\.) - numeric lists
+ // )?
+ // [ \t]* - trailing whitespace
+const MARKDOWN_PREFIX = /^([ \t]*\>)*(([ \t]*#*)|([ \t]*[\*\+-])|([ \t]*[\d]+\.))?[ \t]*/
+
+//matches strings that end with a newline followed by some whitespace
+const NEWLINE_SUFFIX = /\n\s*$/
+
+// transformation rule 2:
+// after a newline, if an ins or del block begins with a markdown line formatting prefix (eg. for a title or list)
+// then that prefix should be moved out of the block
+// also, if an ins block begins with a formatting prefix and follows immediately after a del block that follows a newline,
+// the prefix should be moved out of the block _and_ an extra newline character should be added to the beginning of it
function applyTransformationRule2(diff) {
- // we need to find markdown prefixes that should be pulled out of added/removed blocks to the start of the line
- // prefixes are matched as follows:
- // ^ - start of line
- // ([ \t]*\>)* - blockquotes (possibly nested)
- // (
- // ([ \t]*#*) - headers
- // |([ \t]+[\*\+-]) - unordered lists
- // |([ \t]+[0-9]+\.) - numeric lists
- // )?
- // [ \t]* - trailing whitespace
- const PREFIX = /^([ \t]*\>)*(([ \t]*#*)|([ \t]*[\*\+-])|([ \t]*[\d]+\.))?[ \t]*/
-
let transformedDiff = []
- return transformedDiff
+ let isNewline = true
+ let newlineString = '\n'
- /// ...
- /*
- transform.forEach(function(item) {
- //newlines are undecorated
- if (item.string == '\n') {
- output += '\n';
+ //iterate the input tokens to create the intermediate representation
+ diff.forEach((currentBlock) => {
- //flag the new line
- newline = true;
- //and record the offset in the output string
- newlineIndex = output.length;
- return
+ if (isNewline && (currentBlock.added || currentBlock.removed) ) {
+ let match = currentBlock.value.match(MARKDOWN_PREFIX)
+ if (match) {
+ let preBlock = {value:match[0]}
+ let postBlock = {added:currentBlock.added, removed:currentBlock.removed, value:currentBlock.value.substring(match[0].length)}
+
+ if (currentBlock.added) {
+ let newlineBlock = {value: newlineString}
+ transformedDiff.push(newlineBlock)
+ }
+ transformedDiff.push(preBlock)
+ transformedDiff.push(postBlock)
+ }
+ else {
+ transformedDiff.push(currentBlock)
+ }
}
-
- //wrap del strings with tags
- if (item.state == SDEL) {
- output += '' + item.string + '';
- //del doesn't reset the newline state
- }
-
- //ins strings have to be handled a little differently:
- //if this is an ins just after a newline, or after a del after a newline,
- //we need to peel off any markdown formatting prefixes and insert them at the beginning of the line outside the del/ins tags
- else if (item.state == SINS && newline) {
- var prestring, poststring;
- var match = item.string.match(PREFIX);
- if (match == null)
- prestring ="";
- else
- prestring = match[0];
-
- poststring = item.string.substring(prestring.length);
-
- output = output.substring(0, newlineIndex) + prestring + output.substring(newlineIndex);
- output += '' + poststring + '';
- newline = false;
- newlineIndex = -1;
-
- }
-
- else if (item.state == SINS) {
- output += '' + item.string + '';
- }
-
- //and just output other strings
else {
- output += item.string;
- //this resets the newline state
- newline = false;
- newlineIndex = -1;
+ transformedDiff.push(currentBlock)
+ isNewline = NEWLINE_SUFFIX.test(currentBlock.value)
+ if (isNewline)
+ newlineString = currentBlock.value.match(NEWLINE_SUFFIX)[0]
}
+ })
- });
-*/
-
+ return transformedDiff
}
//returns true if the given diff block contains a newline element
function isMultilineDiffBlock({value}) {
- return value.find(word => word == '\n')
+ return value.indexOf('\n') != -1
}
//returns an array of diff blocks that have the same added, removed fields as the given one
-//but with the array of words split by newlines
+//but with the string split by newlines
//if the diff block has no newlines, an array containing only that diff will be returned
//if the diff block has newlines, the resulting array will have a series of blocks,
// each of which subsequent to the first block will begin with a newline
//if the diff block begins with a newline, the returned array will begin with an empty diff
function splitMultilineDiffBlock({added, removed, value}) {
//find the indices of the diff block that coorespond to newlines
- const splits = findIndicesOf(value, str => str=='\n')
+ const splits = indicesOf(value, c => (c=='\n') )
splits.push(value.length)
//create a range from each index
- const ranges = splits.reduce(
+ const ranges = splits.reduce(
//the accumulator is a structure with the last index and the list of ranges
//the ranges are a {start, end} structure
({last, ranges}, i) => {
@@ -249,16 +210,16 @@ function splitMultilineDiffBlock({added, removed, value}) {
//map the ranges into blocks
const blocks = ranges.map(
//each block is the same as the given original block, but with the values split at newlines
- ({start, end}) => ({added, removed, value:value.slice(start, end)})
+ ({start, end}) => ({added, removed, value:value.substring(start, end)})
)
- console.log({value, splits, ranges, blocks})
+ //console.log({value, splits, ranges, blocks})
return blocks
}
-//collect all the indices of the given array that satisfy the test function
-const findIndicesOf = (array, test) => array.reduce(
+//collect all the indices of the given string that satisfy the test function
+const indicesOf = (string, test) => string.split('').reduce(
//add indexes that satisfy the test function to the array
(acc, x, i) => (test(x) ? acc.concat([i]) : acc ),
//start with the empty array
diff --git a/test/dubdiffMarkdown.js b/test/dubdiffMarkdown.js
index a3715fa..a66be77 100644
--- a/test/dubdiffMarkdown.js
+++ b/test/dubdiffMarkdown.js
@@ -21,21 +21,21 @@ describe('dubdiff', () => {
expect(diff(
'This is a smlb sentnce with no errors.',
'This is a simple sentence with no errors.'
- )).to.equal('This is a [-smlb sentnce-] {+simple sentence+} with no errors.')
+ )).to.equal('This is a [-smlb sentnce -]{+simple sentence +}with no errors.')
})
it('plaintext diffs with word deletion', ()=>{
expect(diff(
'Gonna delete a word.',
'Gonna delete word.'
- )).to.equal('Gonna delete [-a-] word.')
+ )).to.equal('Gonna delete [-a -]word.')
})
it('plaintext diffs with word insertion', ()=>{
expect(diff(
'Gonna delete word.',
'Gonna delete a word.'
- )).to.equal('Gonna delete {+a+} word.')
+ )).to.equal('Gonna delete {+a +}word.')
})
it('reorganizes insertions after multiline deletions', ()=>{
@@ -43,6 +43,32 @@ describe('dubdiff', () => {
`# Title
other`,
`# Subtitle`
- )).to.equal('# [-Title-] {+Subtitle+}[-\nother-]')
+ )).to.equal('# [-Title-]{+Subtitle+}[-\nother-]')
+ })
+
+ it('pulls prefixes out of ins or del blocks after newline', () => {
+ expect(diff(
+ '# Title\n > hello',
+ '# Title\n - goodbye'
+ )).to.equal('# Title\n > [-hello-]\n - {+goodbye+}')
+ })
+
+ it('respects bold and italic boundaries', () => {
+ expect(diff(
+ 'This *word* **isn\'t** changed.',
+ 'This *other one* **is** changed.'
+ )).to.equal('This *[-word-]{+other one+}* **[-isn\'t-]{+is+}** changed.')
+ })
+ it('respects link boundaries in link text', () => {
+ expect(diff(
+ 'This [link](https://somewhere.com) is the same.',
+ 'This [target](https://somewhere.com) changed.'
+ )).to.equal('This [[-link-]{+target+}](https://somewhere.com) [-is the same-]{+changed+}.')
+ })
+ it('respects link boundaries in link target', () => {
+ expect(diff(
+ 'This [link](https://somewhere.com) is the same.',
+ 'This [link](https://somewhere.org) changed.'
+ )).to.equal('This [link](https://somewhere.[-com-]{+org+}) [-is the same-]{+changed+}.')
})
})
\ No newline at end of file
diff --git a/test/dubdiffPlaintext.js b/test/dubdiffPlaintext.js
index 8fdb1f3..0648e9e 100644
--- a/test/dubdiffPlaintext.js
+++ b/test/dubdiffPlaintext.js
@@ -27,7 +27,7 @@ describe('dubdiff', () => {
expect(diff(
'This is a smlb sentnce with no errors.',
'This is a simple sentence with no errors.'
- )).to.equal('This is a [-smlb sentnce-]{+simple sentence+} with no errors.')
+ )).to.equal('This is a [-smlb sentnce -]{+simple sentence +}with no errors.')
})
it('diffs with word deletion', ()=>{
@@ -60,4 +60,10 @@ describe('dubdiff', () => {
'there\n'
)).to.equal('there\n')
})
+ it('treats punctuation separately', () => {
+ expect(diff(
+ 'Hello world.',
+ 'Hello, world.'
+ )).to.equal('Hello{+, +}world.')
+ })
})
\ No newline at end of file
diff --git a/webpack.config.js b/webpack.config.js
index c8a4dd4..334d5de 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -17,6 +17,7 @@ module.exports = {
compact: "true"
}
},
+ { test: /\.json$/, loader: "json-loader" },
]
},
};