Kajiki-0.4.4/0000775000175000017500000000000012212721424013140 5ustar nandonando00000000000000Kajiki-0.4.4/LICENSE.rst0000664000175000017500000000206712175537504014775 0ustar nandonando00000000000000License ======= Copyright (c) 2010-2013 Rick Copeland Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Kajiki-0.4.4/kajiki/0000775000175000017500000000000012212721424014402 5ustar nandonando00000000000000Kajiki-0.4.4/kajiki/entities.py0000664000175000017500000016210712175512112016607 0ustar nandonando00000000000000# -*- coding: utf-8 -*- '''python3.3/html/entities.py, plus HTMLParser.decode(), for Python 2 compat''' from __future__ import (absolute_import, division, print_function, unicode_literals) import re def unescape(s): '''Decode HTML entities.''' if '&' not in s: return s return UNESCAPE_RE.sub(_replace_entities, s) try: UNESCAPE_RE = re.compile(r"&(#?[xX]?(?:[0-9a-fA-F]+;|\w{1,32};?))", flags=re.ASCII) except AttributeError: UNESCAPE_RE = re.compile(br"&(#?[xX]?(?:[0-9a-fA-F]+;|\w{1,32};?))") def _replace_entities(s): s = s.groups()[0] try: if s[0] == "#": s = s[1:] if s[0] in ['x', 'X']: c = int(s[1:].rstrip(';'), 16) else: c = int(s.rstrip(';')) return chr(c) except ValueError: return '&#' + s else: if s in html5: return html5[s] elif s.endswith(';'): return '&' + s for x in range(2, len(s)): if s[:x] in html5: return html5[s[:x]] + s[x:] else: return '&' + s # Maps HTML5 named character references to the equivalent Unicode character(s) html5 = { 'Aacute': '\xc1', 'aacute': '\xe1', 'Aacute;': '\xc1', 'aacute;': '\xe1', 'Abreve;': '\u0102', 'abreve;': '\u0103', 'ac;': '\u223e', 'acd;': '\u223f', 'acE;': '\u223e\u0333', 'Acirc': '\xc2', 'acirc': '\xe2', 'Acirc;': '\xc2', 'acirc;': '\xe2', 'acute': '\xb4', 'acute;': '\xb4', 'Acy;': '\u0410', 'acy;': '\u0430', 'AElig': '\xc6', 'aelig': '\xe6', 'AElig;': '\xc6', 'aelig;': '\xe6', 'af;': '\u2061', 'Afr;': '\U0001d504', 'afr;': '\U0001d51e', 'Agrave': '\xc0', 'agrave': '\xe0', 'Agrave;': '\xc0', 'agrave;': '\xe0', 'alefsym;': '\u2135', 'aleph;': '\u2135', 'Alpha;': '\u0391', 'alpha;': '\u03b1', 'Amacr;': '\u0100', 'amacr;': '\u0101', 'amalg;': '\u2a3f', 'AMP': '&', 'amp': '&', 'AMP;': '&', 'amp;': '&', '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;': '\xc5', 'angzarr;': '\u237c', 'Aogon;': '\u0104', 'aogon;': '\u0105', 'Aopf;': '\U0001d538', 'aopf;': '\U0001d552', 'ap;': '\u2248', 'apacir;': '\u2a6f', 'apE;': '\u2a70', 'ape;': '\u224a', 'apid;': '\u224b', 'apos;': "'", 'ApplyFunction;': '\u2061', 'approx;': '\u2248', 'approxeq;': '\u224a', 'Aring': '\xc5', 'aring': '\xe5', 'Aring;': '\xc5', 'aring;': '\xe5', 'Ascr;': '\U0001d49c', 'ascr;': '\U0001d4b6', 'Assign;': '\u2254', 'ast;': '*', 'asymp;': '\u2248', 'asympeq;': '\u224d', 'Atilde': '\xc3', 'atilde': '\xe3', 'Atilde;': '\xc3', 'atilde;': '\xe3', 'Auml': '\xc4', 'auml': '\xe4', 'Auml;': '\xc4', 'auml;': '\xe4', '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;': '\U0001d505', 'bfr;': '\U0001d51f', '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;': '=\u20e5', 'bnequiv;': '\u2261\u20e5', 'bNot;': '\u2aed', 'bnot;': '\u2310', 'Bopf;': '\U0001d539', 'bopf;': '\U0001d553', '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': '\xa6', 'brvbar;': '\xa6', 'Bscr;': '\u212c', 'bscr;': '\U0001d4b7', 'bsemi;': '\u204f', 'bsim;': '\u223d', 'bsime;': '\u22cd', 'bsol;': '\\', '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': '\xc7', 'ccedil': '\xe7', 'Ccedil;': '\xc7', 'ccedil;': '\xe7', 'Ccirc;': '\u0108', 'ccirc;': '\u0109', 'Cconint;': '\u2230', 'ccups;': '\u2a4c', 'ccupssm;': '\u2a50', 'Cdot;': '\u010a', 'cdot;': '\u010b', 'cedil': '\xb8', 'cedil;': '\xb8', 'Cedilla;': '\xb8', 'cemptyv;': '\u29b2', 'cent': '\xa2', 'cent;': '\xa2', 'CenterDot;': '\xb7', 'centerdot;': '\xb7', 'Cfr;': '\u212d', 'cfr;': '\U0001d520', '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;': '\xae', '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;': ':', 'Colone;': '\u2a74', 'colone;': '\u2254', 'coloneq;': '\u2254', 'comma;': ',', 'commat;': '@', 'comp;': '\u2201', 'compfn;': '\u2218', 'complement;': '\u2201', 'complexes;': '\u2102', 'cong;': '\u2245', 'congdot;': '\u2a6d', 'Congruent;': '\u2261', 'Conint;': '\u222f', 'conint;': '\u222e', 'ContourIntegral;': '\u222e', 'Copf;': '\u2102', 'copf;': '\U0001d554', 'coprod;': '\u2210', 'Coproduct;': '\u2210', 'COPY': '\xa9', 'copy': '\xa9', 'COPY;': '\xa9', 'copy;': '\xa9', 'copysr;': '\u2117', 'CounterClockwiseContourIntegral;': '\u2233', 'crarr;': '\u21b5', 'Cross;': '\u2a2f', 'cross;': '\u2717', 'Cscr;': '\U0001d49e', 'cscr;': '\U0001d4b8', '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': '\xa4', 'curren;': '\xa4', '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': '\xb0', 'deg;': '\xb0', 'Del;': '\u2207', 'Delta;': '\u0394', 'delta;': '\u03b4', 'demptyv;': '\u29b1', 'dfisht;': '\u297f', 'Dfr;': '\U0001d507', 'dfr;': '\U0001d521', 'dHar;': '\u2965', 'dharl;': '\u21c3', 'dharr;': '\u21c2', 'DiacriticalAcute;': '\xb4', 'DiacriticalDot;': '\u02d9', 'DiacriticalDoubleAcute;': '\u02dd', 'DiacriticalGrave;': '`', 'DiacriticalTilde;': '\u02dc', 'diam;': '\u22c4', 'Diamond;': '\u22c4', 'diamond;': '\u22c4', 'diamondsuit;': '\u2666', 'diams;': '\u2666', 'die;': '\xa8', 'DifferentialD;': '\u2146', 'digamma;': '\u03dd', 'disin;': '\u22f2', 'div;': '\xf7', 'divide': '\xf7', 'divide;': '\xf7', 'divideontimes;': '\u22c7', 'divonx;': '\u22c7', 'DJcy;': '\u0402', 'djcy;': '\u0452', 'dlcorn;': '\u231e', 'dlcrop;': '\u230d', 'dollar;': '$', 'Dopf;': '\U0001d53b', 'dopf;': '\U0001d555', 'Dot;': '\xa8', 'dot;': '\u02d9', 'DotDot;': '\u20dc', 'doteq;': '\u2250', 'doteqdot;': '\u2251', 'DotEqual;': '\u2250', 'dotminus;': '\u2238', 'dotplus;': '\u2214', 'dotsquare;': '\u22a1', 'doublebarwedge;': '\u2306', 'DoubleContourIntegral;': '\u222f', 'DoubleDot;': '\xa8', '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;': '\U0001d49f', 'dscr;': '\U0001d4b9', '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': '\xc9', 'eacute': '\xe9', 'Eacute;': '\xc9', 'eacute;': '\xe9', 'easter;': '\u2a6e', 'Ecaron;': '\u011a', 'ecaron;': '\u011b', 'ecir;': '\u2256', 'Ecirc': '\xca', 'ecirc': '\xea', 'Ecirc;': '\xca', 'ecirc;': '\xea', 'ecolon;': '\u2255', 'Ecy;': '\u042d', 'ecy;': '\u044d', 'eDDot;': '\u2a77', 'Edot;': '\u0116', 'eDot;': '\u2251', 'edot;': '\u0117', 'ee;': '\u2147', 'efDot;': '\u2252', 'Efr;': '\U0001d508', 'efr;': '\U0001d522', 'eg;': '\u2a9a', 'Egrave': '\xc8', 'egrave': '\xe8', 'Egrave;': '\xc8', 'egrave;': '\xe8', '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', 'emsp13;': '\u2004', 'emsp14;': '\u2005', 'emsp;': '\u2003', 'ENG;': '\u014a', 'eng;': '\u014b', 'ensp;': '\u2002', 'Eogon;': '\u0118', 'eogon;': '\u0119', 'Eopf;': '\U0001d53c', 'eopf;': '\U0001d556', '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;': '=', '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': '\xd0', 'eth': '\xf0', 'ETH;': '\xd0', 'eth;': '\xf0', 'Euml': '\xcb', 'euml': '\xeb', 'Euml;': '\xcb', 'euml;': '\xeb', 'euro;': '\u20ac', 'excl;': '!', '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;': '\U0001d509', 'ffr;': '\U0001d523', 'filig;': '\ufb01', 'FilledSmallSquare;': '\u25fc', 'FilledVerySmallSquare;': '\u25aa', 'fjlig;': 'fj', 'flat;': '\u266d', 'fllig;': '\ufb02', 'fltns;': '\u25b1', 'fnof;': '\u0192', 'Fopf;': '\U0001d53d', 'fopf;': '\U0001d557', 'ForAll;': '\u2200', 'forall;': '\u2200', 'fork;': '\u22d4', 'forkv;': '\u2ad9', 'Fouriertrf;': '\u2131', 'fpartint;': '\u2a0d', 'frac12': '\xbd', 'frac12;': '\xbd', 'frac13;': '\u2153', 'frac14': '\xbc', 'frac14;': '\xbc', 'frac15;': '\u2155', 'frac16;': '\u2159', 'frac18;': '\u215b', 'frac23;': '\u2154', 'frac25;': '\u2156', 'frac34': '\xbe', 'frac34;': '\xbe', 'frac35;': '\u2157', 'frac38;': '\u215c', 'frac45;': '\u2158', 'frac56;': '\u215a', 'frac58;': '\u215d', 'frac78;': '\u215e', 'frasl;': '\u2044', 'frown;': '\u2322', 'Fscr;': '\u2131', 'fscr;': '\U0001d4bb', '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;': '\U0001d50a', 'gfr;': '\U0001d524', '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;': '\U0001d53e', 'gopf;': '\U0001d558', 'grave;': '`', 'GreaterEqual;': '\u2265', 'GreaterEqualLess;': '\u22db', 'GreaterFullEqual;': '\u2267', 'GreaterGreater;': '\u2aa2', 'GreaterLess;': '\u2277', 'GreaterSlantEqual;': '\u2a7e', 'GreaterTilde;': '\u2273', 'Gscr;': '\U0001d4a2', 'gscr;': '\u210a', 'gsim;': '\u2273', 'gsime;': '\u2a8e', 'gsiml;': '\u2a90', 'GT': '>', 'gt': '>', 'GT;': '>', 'Gt;': '\u226b', 'gt;': '>', '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;': '\xbd', 'hamilt;': '\u210b', 'HARDcy;': '\u042a', 'hardcy;': '\u044a', 'hArr;': '\u21d4', 'harr;': '\u2194', 'harrcir;': '\u2948', 'harrw;': '\u21ad', 'Hat;': '^', 'hbar;': '\u210f', 'Hcirc;': '\u0124', 'hcirc;': '\u0125', 'hearts;': '\u2665', 'heartsuit;': '\u2665', 'hellip;': '\u2026', 'hercon;': '\u22b9', 'Hfr;': '\u210c', 'hfr;': '\U0001d525', 'HilbertSpace;': '\u210b', 'hksearow;': '\u2925', 'hkswarow;': '\u2926', 'hoarr;': '\u21ff', 'homtht;': '\u223b', 'hookleftarrow;': '\u21a9', 'hookrightarrow;': '\u21aa', 'Hopf;': '\u210d', 'hopf;': '\U0001d559', 'horbar;': '\u2015', 'HorizontalLine;': '\u2500', 'Hscr;': '\u210b', 'hscr;': '\U0001d4bd', 'hslash;': '\u210f', 'Hstrok;': '\u0126', 'hstrok;': '\u0127', 'HumpDownHump;': '\u224e', 'HumpEqual;': '\u224f', 'hybull;': '\u2043', 'hyphen;': '\u2010', 'Iacute': '\xcd', 'iacute': '\xed', 'Iacute;': '\xcd', 'iacute;': '\xed', 'ic;': '\u2063', 'Icirc': '\xce', 'icirc': '\xee', 'Icirc;': '\xce', 'icirc;': '\xee', 'Icy;': '\u0418', 'icy;': '\u0438', 'Idot;': '\u0130', 'IEcy;': '\u0415', 'iecy;': '\u0435', 'iexcl': '\xa1', 'iexcl;': '\xa1', 'iff;': '\u21d4', 'Ifr;': '\u2111', 'ifr;': '\U0001d526', 'Igrave': '\xcc', 'igrave': '\xec', 'Igrave;': '\xcc', 'igrave;': '\xec', '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;': '\U0001d540', 'iopf;': '\U0001d55a', 'Iota;': '\u0399', 'iota;': '\u03b9', 'iprod;': '\u2a3c', 'iquest': '\xbf', 'iquest;': '\xbf', 'Iscr;': '\u2110', 'iscr;': '\U0001d4be', 'isin;': '\u2208', 'isindot;': '\u22f5', 'isinE;': '\u22f9', 'isins;': '\u22f4', 'isinsv;': '\u22f3', 'isinv;': '\u2208', 'it;': '\u2062', 'Itilde;': '\u0128', 'itilde;': '\u0129', 'Iukcy;': '\u0406', 'iukcy;': '\u0456', 'Iuml': '\xcf', 'iuml': '\xef', 'Iuml;': '\xcf', 'iuml;': '\xef', 'Jcirc;': '\u0134', 'jcirc;': '\u0135', 'Jcy;': '\u0419', 'jcy;': '\u0439', 'Jfr;': '\U0001d50d', 'jfr;': '\U0001d527', 'jmath;': '\u0237', 'Jopf;': '\U0001d541', 'jopf;': '\U0001d55b', 'Jscr;': '\U0001d4a5', 'jscr;': '\U0001d4bf', 'Jsercy;': '\u0408', 'jsercy;': '\u0458', 'Jukcy;': '\u0404', 'jukcy;': '\u0454', 'Kappa;': '\u039a', 'kappa;': '\u03ba', 'kappav;': '\u03f0', 'Kcedil;': '\u0136', 'kcedil;': '\u0137', 'Kcy;': '\u041a', 'kcy;': '\u043a', 'Kfr;': '\U0001d50e', 'kfr;': '\U0001d528', 'kgreen;': '\u0138', 'KHcy;': '\u0425', 'khcy;': '\u0445', 'KJcy;': '\u040c', 'kjcy;': '\u045c', 'Kopf;': '\U0001d542', 'kopf;': '\U0001d55c', 'Kscr;': '\U0001d4a6', 'kscr;': '\U0001d4c0', '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': '\xab', 'laquo;': '\xab', '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;': '{', 'lbrack;': '[', 'lbrke;': '\u298b', 'lbrksld;': '\u298f', 'lbrkslu;': '\u298d', 'Lcaron;': '\u013d', 'lcaron;': '\u013e', 'Lcedil;': '\u013b', 'lcedil;': '\u013c', 'lceil;': '\u2308', 'lcub;': '{', '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;': '\U0001d50f', 'lfr;': '\U0001d529', '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;': '\U0001d543', 'lopf;': '\U0001d55d', 'loplus;': '\u2a2d', 'lotimes;': '\u2a34', 'lowast;': '\u2217', 'lowbar;': '_', 'LowerLeftArrow;': '\u2199', 'LowerRightArrow;': '\u2198', 'loz;': '\u25ca', 'lozenge;': '\u25ca', 'lozf;': '\u29eb', 'lpar;': '(', 'lparlt;': '\u2993', 'lrarr;': '\u21c6', 'lrcorner;': '\u231f', 'lrhar;': '\u21cb', 'lrhard;': '\u296d', 'lrm;': '\u200e', 'lrtri;': '\u22bf', 'lsaquo;': '\u2039', 'Lscr;': '\u2112', 'lscr;': '\U0001d4c1', 'Lsh;': '\u21b0', 'lsh;': '\u21b0', 'lsim;': '\u2272', 'lsime;': '\u2a8d', 'lsimg;': '\u2a8f', 'lsqb;': '[', 'lsquo;': '\u2018', 'lsquor;': '\u201a', 'Lstrok;': '\u0141', 'lstrok;': '\u0142', 'LT': '<', 'lt': '<', 'LT;': '<', 'Lt;': '\u226a', 'lt;': '<', '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': '\xaf', 'macr;': '\xaf', '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;': '\U0001d510', 'mfr;': '\U0001d52a', 'mho;': '\u2127', 'micro': '\xb5', 'micro;': '\xb5', 'mid;': '\u2223', 'midast;': '*', 'midcir;': '\u2af0', 'middot': '\xb7', 'middot;': '\xb7', 'minus;': '\u2212', 'minusb;': '\u229f', 'minusd;': '\u2238', 'minusdu;': '\u2a2a', 'MinusPlus;': '\u2213', 'mlcp;': '\u2adb', 'mldr;': '\u2026', 'mnplus;': '\u2213', 'models;': '\u22a7', 'Mopf;': '\U0001d544', 'mopf;': '\U0001d55e', 'mp;': '\u2213', 'Mscr;': '\u2133', 'mscr;': '\U0001d4c2', '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': '\xa0', 'nbsp;': '\xa0', '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;': '\n', 'nexist;': '\u2204', 'nexists;': '\u2204', 'Nfr;': '\U0001d511', 'nfr;': '\U0001d52b', '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;': '\xa0', 'Nopf;': '\u2115', 'nopf;': '\U0001d55f', 'not': '\xac', 'Not;': '\u2aec', 'not;': '\xac', '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;': '\U0001d4a9', 'nscr;': '\U0001d4c3', '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': '\xd1', 'ntilde': '\xf1', 'Ntilde;': '\xd1', 'ntilde;': '\xf1', 'ntlg;': '\u2278', 'ntriangleleft;': '\u22ea', 'ntrianglelefteq;': '\u22ec', 'ntriangleright;': '\u22eb', 'ntrianglerighteq;': '\u22ed', 'Nu;': '\u039d', 'nu;': '\u03bd', 'num;': '#', 'numero;': '\u2116', 'numsp;': '\u2007', 'nvap;': '\u224d\u20d2', 'nVDash;': '\u22af', 'nVdash;': '\u22ae', 'nvDash;': '\u22ad', 'nvdash;': '\u22ac', 'nvge;': '\u2265\u20d2', 'nvgt;': '>\u20d2', 'nvHarr;': '\u2904', 'nvinfin;': '\u29de', 'nvlArr;': '\u2902', 'nvle;': '\u2264\u20d2', 'nvlt;': '<\u20d2', 'nvltrie;': '\u22b4\u20d2', 'nvrArr;': '\u2903', 'nvrtrie;': '\u22b5\u20d2', 'nvsim;': '\u223c\u20d2', 'nwarhk;': '\u2923', 'nwArr;': '\u21d6', 'nwarr;': '\u2196', 'nwarrow;': '\u2196', 'nwnear;': '\u2927', 'Oacute': '\xd3', 'oacute': '\xf3', 'Oacute;': '\xd3', 'oacute;': '\xf3', 'oast;': '\u229b', 'ocir;': '\u229a', 'Ocirc': '\xd4', 'ocirc': '\xf4', 'Ocirc;': '\xd4', 'ocirc;': '\xf4', 'Ocy;': '\u041e', 'ocy;': '\u043e', 'odash;': '\u229d', 'Odblac;': '\u0150', 'odblac;': '\u0151', 'odiv;': '\u2a38', 'odot;': '\u2299', 'odsold;': '\u29bc', 'OElig;': '\u0152', 'oelig;': '\u0153', 'ofcir;': '\u29bf', 'Ofr;': '\U0001d512', 'ofr;': '\U0001d52c', 'ogon;': '\u02db', 'Ograve': '\xd2', 'ograve': '\xf2', 'Ograve;': '\xd2', 'ograve;': '\xf2', '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;': '\U0001d546', 'oopf;': '\U0001d560', 'opar;': '\u29b7', 'OpenCurlyDoubleQuote;': '\u201c', 'OpenCurlyQuote;': '\u2018', 'operp;': '\u29b9', 'oplus;': '\u2295', 'Or;': '\u2a54', 'or;': '\u2228', 'orarr;': '\u21bb', 'ord;': '\u2a5d', 'order;': '\u2134', 'orderof;': '\u2134', 'ordf': '\xaa', 'ordf;': '\xaa', 'ordm': '\xba', 'ordm;': '\xba', 'origof;': '\u22b6', 'oror;': '\u2a56', 'orslope;': '\u2a57', 'orv;': '\u2a5b', 'oS;': '\u24c8', 'Oscr;': '\U0001d4aa', 'oscr;': '\u2134', 'Oslash': '\xd8', 'oslash': '\xf8', 'Oslash;': '\xd8', 'oslash;': '\xf8', 'osol;': '\u2298', 'Otilde': '\xd5', 'otilde': '\xf5', 'Otilde;': '\xd5', 'otilde;': '\xf5', 'Otimes;': '\u2a37', 'otimes;': '\u2297', 'otimesas;': '\u2a36', 'Ouml': '\xd6', 'ouml': '\xf6', 'Ouml;': '\xd6', 'ouml;': '\xf6', 'ovbar;': '\u233d', 'OverBar;': '\u203e', 'OverBrace;': '\u23de', 'OverBracket;': '\u23b4', 'OverParenthesis;': '\u23dc', 'par;': '\u2225', 'para': '\xb6', 'para;': '\xb6', 'parallel;': '\u2225', 'parsim;': '\u2af3', 'parsl;': '\u2afd', 'part;': '\u2202', 'PartialD;': '\u2202', 'Pcy;': '\u041f', 'pcy;': '\u043f', 'percnt;': '%', 'period;': '.', 'permil;': '\u2030', 'perp;': '\u22a5', 'pertenk;': '\u2031', 'Pfr;': '\U0001d513', 'pfr;': '\U0001d52d', '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;': '+', 'plusacir;': '\u2a23', 'plusb;': '\u229e', 'pluscir;': '\u2a22', 'plusdo;': '\u2214', 'plusdu;': '\u2a25', 'pluse;': '\u2a72', 'PlusMinus;': '\xb1', 'plusmn': '\xb1', 'plusmn;': '\xb1', 'plussim;': '\u2a26', 'plustwo;': '\u2a27', 'pm;': '\xb1', 'Poincareplane;': '\u210c', 'pointint;': '\u2a15', 'Popf;': '\u2119', 'popf;': '\U0001d561', 'pound': '\xa3', 'pound;': '\xa3', '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;': '\U0001d4ab', 'pscr;': '\U0001d4c5', 'Psi;': '\u03a8', 'psi;': '\u03c8', 'puncsp;': '\u2008', 'Qfr;': '\U0001d514', 'qfr;': '\U0001d52e', 'qint;': '\u2a0c', 'Qopf;': '\u211a', 'qopf;': '\U0001d562', 'qprime;': '\u2057', 'Qscr;': '\U0001d4ac', 'qscr;': '\U0001d4c6', 'quaternions;': '\u210d', 'quatint;': '\u2a16', 'quest;': '?', 'questeq;': '\u225f', 'QUOT': '"', 'quot': '"', 'QUOT;': '"', 'quot;': '"', 'rAarr;': '\u21db', 'race;': '\u223d\u0331', 'Racute;': '\u0154', 'racute;': '\u0155', 'radic;': '\u221a', 'raemptyv;': '\u29b3', 'Rang;': '\u27eb', 'rang;': '\u27e9', 'rangd;': '\u2992', 'range;': '\u29a5', 'rangle;': '\u27e9', 'raquo': '\xbb', 'raquo;': '\xbb', '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;': '}', 'rbrack;': ']', 'rbrke;': '\u298c', 'rbrksld;': '\u298e', 'rbrkslu;': '\u2990', 'Rcaron;': '\u0158', 'rcaron;': '\u0159', 'Rcedil;': '\u0156', 'rcedil;': '\u0157', 'rceil;': '\u2309', 'rcub;': '}', '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': '\xae', 'reg': '\xae', 'REG;': '\xae', 'reg;': '\xae', 'ReverseElement;': '\u220b', 'ReverseEquilibrium;': '\u21cb', 'ReverseUpEquilibrium;': '\u296f', 'rfisht;': '\u297d', 'rfloor;': '\u230b', 'Rfr;': '\u211c', 'rfr;': '\U0001d52f', '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;': '\U0001d563', 'roplus;': '\u2a2e', 'rotimes;': '\u2a35', 'RoundImplies;': '\u2970', 'rpar;': ')', 'rpargt;': '\u2994', 'rppolint;': '\u2a12', 'rrarr;': '\u21c9', 'Rrightarrow;': '\u21db', 'rsaquo;': '\u203a', 'Rscr;': '\u211b', 'rscr;': '\U0001d4c7', 'Rsh;': '\u21b1', 'rsh;': '\u21b1', 'rsqb;': ']', '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': '\xa7', 'sect;': '\xa7', 'semi;': ';', 'seswar;': '\u2929', 'setminus;': '\u2216', 'setmn;': '\u2216', 'sext;': '\u2736', 'Sfr;': '\U0001d516', 'sfr;': '\U0001d530', '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': '\xad', 'shy;': '\xad', '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;': '/', 'solb;': '\u29c4', 'solbar;': '\u233f', 'Sopf;': '\U0001d54a', 'sopf;': '\U0001d564', '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;': '\U0001d4ae', 'sscr;': '\U0001d4c8', 'ssetmn;': '\u2216', 'ssmile;': '\u2323', 'sstarf;': '\u22c6', 'Star;': '\u22c6', 'star;': '\u2606', 'starf;': '\u2605', 'straightepsilon;': '\u03f5', 'straightphi;': '\u03d5', 'strns;': '\xaf', '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', 'sup1': '\xb9', 'sup1;': '\xb9', 'sup2': '\xb2', 'sup2;': '\xb2', 'sup3': '\xb3', 'sup3;': '\xb3', 'Sup;': '\u22d1', 'sup;': '\u2283', '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': '\xdf', 'szlig;': '\xdf', 'Tab;': '\t', '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;': '\U0001d517', 'tfr;': '\U0001d531', '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': '\xde', 'thorn': '\xfe', 'THORN;': '\xde', 'thorn;': '\xfe', 'Tilde;': '\u223c', 'tilde;': '\u02dc', 'TildeEqual;': '\u2243', 'TildeFullEqual;': '\u2245', 'TildeTilde;': '\u2248', 'times': '\xd7', 'times;': '\xd7', 'timesb;': '\u22a0', 'timesbar;': '\u2a31', 'timesd;': '\u2a30', 'tint;': '\u222d', 'toea;': '\u2928', 'top;': '\u22a4', 'topbot;': '\u2336', 'topcir;': '\u2af1', 'Topf;': '\U0001d54b', 'topf;': '\U0001d565', '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;': '\U0001d4af', 'tscr;': '\U0001d4c9', 'TScy;': '\u0426', 'tscy;': '\u0446', 'TSHcy;': '\u040b', 'tshcy;': '\u045b', 'Tstrok;': '\u0166', 'tstrok;': '\u0167', 'twixt;': '\u226c', 'twoheadleftarrow;': '\u219e', 'twoheadrightarrow;': '\u21a0', 'Uacute': '\xda', 'uacute': '\xfa', 'Uacute;': '\xda', 'uacute;': '\xfa', 'Uarr;': '\u219f', 'uArr;': '\u21d1', 'uarr;': '\u2191', 'Uarrocir;': '\u2949', 'Ubrcy;': '\u040e', 'ubrcy;': '\u045e', 'Ubreve;': '\u016c', 'ubreve;': '\u016d', 'Ucirc': '\xdb', 'ucirc': '\xfb', 'Ucirc;': '\xdb', 'ucirc;': '\xfb', 'Ucy;': '\u0423', 'ucy;': '\u0443', 'udarr;': '\u21c5', 'Udblac;': '\u0170', 'udblac;': '\u0171', 'udhar;': '\u296e', 'ufisht;': '\u297e', 'Ufr;': '\U0001d518', 'ufr;': '\U0001d532', 'Ugrave': '\xd9', 'ugrave': '\xf9', 'Ugrave;': '\xd9', 'ugrave;': '\xf9', 'uHar;': '\u2963', 'uharl;': '\u21bf', 'uharr;': '\u21be', 'uhblk;': '\u2580', 'ulcorn;': '\u231c', 'ulcorner;': '\u231c', 'ulcrop;': '\u230f', 'ultri;': '\u25f8', 'Umacr;': '\u016a', 'umacr;': '\u016b', 'uml': '\xa8', 'uml;': '\xa8', 'UnderBar;': '_', 'UnderBrace;': '\u23df', 'UnderBracket;': '\u23b5', 'UnderParenthesis;': '\u23dd', 'Union;': '\u22c3', 'UnionPlus;': '\u228e', 'Uogon;': '\u0172', 'uogon;': '\u0173', 'Uopf;': '\U0001d54c', 'uopf;': '\U0001d566', '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;': '\U0001d4b0', 'uscr;': '\U0001d4ca', 'utdot;': '\u22f0', 'Utilde;': '\u0168', 'utilde;': '\u0169', 'utri;': '\u25b5', 'utrif;': '\u25b4', 'uuarr;': '\u21c8', 'Uuml': '\xdc', 'uuml': '\xfc', 'Uuml;': '\xdc', 'uuml;': '\xfc', '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;': '|', 'Vert;': '\u2016', 'vert;': '|', 'VerticalBar;': '\u2223', 'VerticalLine;': '|', 'VerticalSeparator;': '\u2758', 'VerticalTilde;': '\u2240', 'VeryThinSpace;': '\u200a', 'Vfr;': '\U0001d519', 'vfr;': '\U0001d533', 'vltri;': '\u22b2', 'vnsub;': '\u2282\u20d2', 'vnsup;': '\u2283\u20d2', 'Vopf;': '\U0001d54d', 'vopf;': '\U0001d567', 'vprop;': '\u221d', 'vrtri;': '\u22b3', 'Vscr;': '\U0001d4b1', 'vscr;': '\U0001d4cb', '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;': '\U0001d51a', 'wfr;': '\U0001d534', 'Wopf;': '\U0001d54e', 'wopf;': '\U0001d568', 'wp;': '\u2118', 'wr;': '\u2240', 'wreath;': '\u2240', 'Wscr;': '\U0001d4b2', 'wscr;': '\U0001d4cc', 'xcap;': '\u22c2', 'xcirc;': '\u25ef', 'xcup;': '\u22c3', 'xdtri;': '\u25bd', 'Xfr;': '\U0001d51b', 'xfr;': '\U0001d535', 'xhArr;': '\u27fa', 'xharr;': '\u27f7', 'Xi;': '\u039e', 'xi;': '\u03be', 'xlArr;': '\u27f8', 'xlarr;': '\u27f5', 'xmap;': '\u27fc', 'xnis;': '\u22fb', 'xodot;': '\u2a00', 'Xopf;': '\U0001d54f', 'xopf;': '\U0001d569', 'xoplus;': '\u2a01', 'xotime;': '\u2a02', 'xrArr;': '\u27f9', 'xrarr;': '\u27f6', 'Xscr;': '\U0001d4b3', 'xscr;': '\U0001d4cd', 'xsqcup;': '\u2a06', 'xuplus;': '\u2a04', 'xutri;': '\u25b3', 'xvee;': '\u22c1', 'xwedge;': '\u22c0', 'Yacute': '\xdd', 'yacute': '\xfd', 'Yacute;': '\xdd', 'yacute;': '\xfd', 'YAcy;': '\u042f', 'yacy;': '\u044f', 'Ycirc;': '\u0176', 'ycirc;': '\u0177', 'Ycy;': '\u042b', 'ycy;': '\u044b', 'yen': '\xa5', 'yen;': '\xa5', 'Yfr;': '\U0001d51c', 'yfr;': '\U0001d536', 'YIcy;': '\u0407', 'yicy;': '\u0457', 'Yopf;': '\U0001d550', 'yopf;': '\U0001d56a', 'Yscr;': '\U0001d4b4', 'yscr;': '\U0001d4ce', 'YUcy;': '\u042e', 'yucy;': '\u044e', 'yuml': '\xff', 'Yuml;': '\u0178', 'yuml;': '\xff', '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;': '\U0001d537', 'ZHcy;': '\u0416', 'zhcy;': '\u0436', 'zigrarr;': '\u21dd', 'Zopf;': '\u2124', 'zopf;': '\U0001d56b', 'Zscr;': '\U0001d4b5', 'zscr;': '\U0001d4cf', 'zwj;': '\u200d', 'zwnj;': '\u200c', } Kajiki-0.4.4/kajiki/ir.py0000664000175000017500000002761012175512112015374 0ustar nandonando00000000000000# -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) from .util import gen_name, flattener from nine import iteritems, nine def generate_python(ir): cur_indent = 0 for node in flattener(ir): if isinstance(node, IndentNode): cur_indent += 4 elif isinstance(node, DedentNode): cur_indent -= 4 for line in node.py(): yield line.indent(cur_indent) class Node(object): def __init__(self): self.filename = '' self.lineno = 0 def py(self): # pragma no cover return [] def __iter__(self): yield self def line(self, text): return PyLine(self.filename, self.lineno, text) class PassNode(Node): def py(self): # 'pass' would result in: TypeError: 'NoneType' object is not iterable yield self.line('yield ""') class HierNode(Node): '''Base for nodes that contain an indented Python block (def, for, if etc.) ''' def __init__(self, body): super(HierNode, self).__init__() self.body = tuple(x for x in body if x is not None) def body_iter(self): for x in optimize(flattener(map(flattener, self.body))): yield x def __iter__(self): yield self yield IndentNode() for x in self.body_iter(): yield x yield DedentNode() class IndentNode(Node): pass class DedentNode(Node): pass class TemplateNode(HierNode): class TemplateTail(Node): def py(self): yield self.line('template = kajiki.Template(template)') def __init__(self, mod_py=None, defs=None): super(TemplateNode, self).__init__(defs) if mod_py is None: mod_py = [] if defs is None: defs = [] self.mod_py = [x for x in mod_py if x is not None] def py(self): yield self.line('class template:') def __iter__(self): for x in flattener(self.mod_py): yield x for x in super(TemplateNode, self).__iter__(): yield x yield self.TemplateTail() class ImportNode(Node): def __init__(self, tpl_name, alias=None): super(ImportNode, self).__init__() self.tpl_name = tpl_name self.alias = alias def py(self): yield self.line( 'local.__kj__.import_(%r, %r, self.__globals__)' % ( self.tpl_name, self.alias)) class IncludeNode(Node): def __init__(self, tpl_name): super(IncludeNode, self).__init__() self.tpl_name = tpl_name def py(self): yield self.line( 'yield local.__kj__.import_(%r, None, self.__globals__).__main__()' % ( self.tpl_name)) class ExtendNode(Node): def __init__(self, tpl_name): super(ExtendNode, self).__init__() self.tpl_name = tpl_name def py(self): yield self.line( 'yield local.__kj__.extend(%r).__main__()' % ( self.tpl_name)) class DefNode(HierNode): prefix = '@kajiki.expose' def __init__(self, decl, *body): super(DefNode, self).__init__(body) self.decl = decl def py(self): yield self.line(self.prefix) yield self.line('def %s:' % (self.decl)) def __iter__(self): yield self yield IndentNode() is_empty = True for x in self.body_iter(): yield x is_empty = False if is_empty: # In Python, a function without a body is a SyntaxError. yield PassNode() # Prevent creation of a function without a body yield DedentNode() class InnerDefNode(DefNode): prefix = '@__kj__.flattener.decorate' class CallNode(HierNode): class CallTail(Node): def __init__(self, call): super(CallNode.CallTail, self).__init__() self.call = call def py(self): yield self.line('yield ' + self.call) def __init__(self, caller, callee, *body): super(CallNode, self).__init__(body) fname = gen_name() self.decl = caller.replace('$caller', fname) self.call = callee.replace('$caller', fname) def py(self): yield self.line('@__kj__.flattener.decorate') yield self.line('def %s:' % (self.decl)) def __iter__(self): yield self yield IndentNode() for x in self.body_iter(): yield x yield DedentNode() yield self.CallTail(self.call) class ForNode(HierNode): def __init__(self, decl, *body): super(ForNode, self).__init__(body) self.decl = decl def py(self): yield self.line('for %s:' % (self.decl)) class WithNode(HierNode): class WithTail(Node): def __init__(self, vars): super(WithNode.WithTail, self).__init__() self.vars = vars def py(self): gen = gen_name() yield self.line('%s = local.__kj__.pop_with()' % gen) for v in self.vars: yield self.line('%s = %s.get(%r)' % (v, gen, v)) # yield self.line('if %s == (): del %s' % (v, v)) def __init__(self, vars, *body): super(WithNode, self).__init__(body) self.vars_text = vars self.vars = dict(var.split('=', 1) for var in vars.split(';')) def py(self): yield self.line( 'local.__kj__.push_with(locals(), %s)' % self.vars_text) for k, v in iteritems(self.vars): yield self.line('%s = %s' % (k, v)) def __iter__(self): yield self for x in self.body_iter(): yield x yield self.WithTail(self.vars) class SwitchNode(HierNode): class SwitchTail(Node): def py(self): yield self.line('local.__kj__.pop_switch()') def __init__(self, decl, *body): super(SwitchNode, self).__init__(body) self.decl = decl def py(self): yield self.line('local.__kj__.push_switch(%s)' % self.decl) def __iter__(self): yield self for x in self.body_iter(): yield x yield self.SwitchTail() class CaseNode(HierNode): def __init__(self, decl, *body): super(CaseNode, self).__init__(body) self.decl = decl def py(self): yield self.line('if local.__kj__.case(%s):' % self.decl) class IfNode(HierNode): def __init__(self, decl, *body): super(IfNode, self).__init__(body) self.decl = decl def py(self): yield self.line('if %s:' % self.decl) class ElseNode(HierNode): def __init__(self, *body): super(ElseNode, self).__init__(body) def py(self): yield self.line('else:') class TextNode(Node): '''Node that outputs Python literals.''' def __init__(self, text, guard=None): super(TextNode, self).__init__() self.text = text self.guard = guard def py(self): s = 'yield %r' % self.text if self.guard: yield self.line('if %s: %s' % (self.guard, s)) else: yield self.line(s) class TranslatableTextNode(TextNode): def py(self): text = self.text.strip() if text: s = 'yield local.__kj__.gettext(%r)' % self.text else: s = 'yield %r' % self.text if self.guard: yield self.line('if %s: %s' % (self.guard, s)) else: yield self.line(s) class ExprNode(Node): '''Node that contains a Python expression to be evaluated when the template is executed. ''' def __init__(self, text, safe=False): super(ExprNode, self).__init__() self.text = text self.safe = safe def py(self): if self.safe: yield self.line('yield %s' % self.text) else: yield self.line('yield self.__kj__.escape(%s)' % self.text) class AttrNode(HierNode): '''Node that renders HTML/XML attributes.''' class AttrTail(Node): def __init__(self, parent): super(AttrNode.AttrTail, self).__init__() self.p = parent def py(self): gen = self.p.genname x = gen_name() yield self.line("%s = self.__kj__.collect(%s())" % (gen, gen)) yield self.line( 'for %s in self.__kj__.render_attrs({%r:%s}, %r):' % (x, self.p.attr, gen, self.p.mode)) yield self.line(' yield %s' % x) def __init__(self, attr, value, guard=None, mode='xml'): super(AttrNode, self).__init__(value) self.attr = attr self.guard = guard self.mode = mode self.genname = gen_name() def py(self): yield self.line('def %s():' % self.genname) def __iter__(self): if self.guard: new_body = IfNode( self.guard, AttrNode(self.attr, value=self.body, mode=self.mode)) for x in new_body: yield x else: yield self yield IndentNode() if self.body: for part in self.body_iter(): yield part else: yield TextNode('') yield DedentNode() yield self.AttrTail(self) class AttrsNode(Node): def __init__(self, attrs, guard=None, mode='xml'): super(AttrsNode, self).__init__() self.attrs = attrs self.guard = guard self.mode = mode def py(self): x = gen_name() def _body(): yield self.line( 'for %s in self.__kj__.render_attrs(%s, %r):' % ( x, self.attrs, self.mode)) yield self.line(' yield %s' % x) if self.guard: yield self.line('if %s:' % self.guard) for l in _body(): yield l.indent() else: for l in _body(): yield l class PythonNode(Node): def __init__(self, *body): super(PythonNode, self).__init__() self.module_level = False blocks = [] for b in body: assert isinstance(b, TextNode) blocks.append(b.text) text = ''.join(blocks) if text[0] == '%': self.module_level = True text = text[1:] self.lines = list(self._normalize(text)) def py(self): for line in self.lines: yield self.line(line) def _normalize(self, text): if text.startswith('#\n'): text = text[2:] prefix = None for line in text.splitlines(): if prefix is None: rest = line.lstrip() prefix = line[:len(line) - len(rest)] assert line.startswith(prefix) yield line[len(prefix):] def optimize(iter_node): last_node = None for node in iter_node: if type(node) == TextNode: if (type(last_node) == TextNode and last_node.guard == node.guard): last_node.text += node.text else: if last_node is not None: yield last_node last_node = node else: if last_node is not None: yield last_node last_node = node if last_node is not None: yield last_node @nine class PyLine(object): def __init__(self, filename, lineno, text, indent=0): self._filename = filename self._lineno = lineno self._text = text self._indent = indent def indent(self, sz=4): return PyLine(self._filename, self._lineno, self._text, self._indent + sz) def __str__(self): return (' ' * self._indent) + self._text if self._lineno: return (' ' * self._indent) + self._text + '\t# %s:%d' % ( self._filename, self._lineno) else: return (' ' * self._indent) + self._text def __repr__(self): return '%s:%s %s' % (self._filename, self._lineno, self) Kajiki-0.4.4/kajiki/template.py0000664000175000017500000002545112175512112016576 0ustar nandonando00000000000000# -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) import re import types from nine import IS_PYTHON2, basestring, str, iteritems try: from functools import update_wrapper except: def update_wrapper(wrapper, wrapped, assigned=('__module__', '__name__', '__doc__'), updated = ('__dict__',)): for attr in assigned: setattr(wrapper, attr, getattr(wrapped, attr)) for attr in updated: getattr(wrapper, attr).update(getattr(wrapped, attr)) return wrapper import kajiki from .util import flattener, literal from .html_utils import HTML_EMPTY_ATTRS from .ir import generate_python from . import lnotab from kajiki import i18n class _obj(object): def __init__(self, **kw): for k, v in iteritems(kw): setattr(self, k, v) class _Template(object): __methods__ = () loader = None base_globals = None filename = None def __init__(self, context=None): if context is None: context = {} self._context = context base_globals = self.base_globals or {} self.__globals__ = dict(base_globals, local=self, self=self, defined=lambda x: x in self.__globals__, literal=literal, Markup=literal, __builtins__=__builtins__, __kj__=kajiki) self.__globals__['value_of'] = self.__globals__.get for k, v in self.__methods__: v = v.bind_instance(self) setattr(self, k, v) self.__globals__[k] = v self.__kj__ = _obj( extend=self._extend, push_switch=self._push_switch, pop_switch=self._pop_switch, case=self._case, import_=self._import, escape=self._escape, gettext=i18n.gettext, render_attrs=self._render_attrs, push_with=self._push_with, pop_with=self._pop_with, collect=self._collect, ) self._switch_stack = [] self._with_stack = [] self.__globals__.update(context) def __iter__(self): '''We convert the chunk to string because it can be of any type -- after all, the template supports expressions such as ${x+y}. Here, ``chunk`` can be the computed expression result. ''' for chunk in self.__main__(): yield str(chunk) def render(self): return ''.join(self) def _push_with(self, lcls, **kw): d = dict((k, lcls.get(k, ())) for k in kw) self._with_stack.append(d) def _pop_with(self): return self._with_stack.pop() def _extend(self, parent): if isinstance(parent, basestring): parent = self.loader.import_(parent) p_inst = parent(self._context) p_globals = p_inst.__globals__ # Find overrides for k, v in iteritems(self.__globals__): if k == '__main__': continue if not isinstance(v, TplFunc): continue p_globals[k] = v # Find inherited funcs for k, v in iteritems(p_inst.__globals__): if k == '__main__': continue if not isinstance(v, TplFunc): continue if k not in self.__globals__: self.__globals__[k] = v if not hasattr(self, k): def _(k=k): '''Capture the 'k' variable in a closure''' def trampoline(*a, **kw): global parent return getattr(parent, k)(*a, **kw) return trampoline setattr(self, k, TplFunc(_()).bind_instance(self)) p_globals['child'] = self p_globals['local'] = p_inst p_globals['self'] = self.__globals__['self'] self.__globals__['parent'] = p_inst self.__globals__['local'] = self return p_inst def _push_switch(self, expr): self._switch_stack.append(expr) def _pop_switch(self): self._switch_stack.pop() def _case(self, obj): return obj == self._switch_stack[-1] def _import(self, name, alias, gbls): tpl_cls = self.loader.import_(name) if alias is None: alias = self.loader.default_alias_for(name) r = gbls[alias] = tpl_cls(gbls) return r def _escape(self, value): "Returns the given HTML with ampersands, carets and quotes encoded." if value is None or isinstance(value, flattener): return value if hasattr(value, '__html__'): return value.__html__() uval = str(value) if self._re_escape.search(uval): # Scan the string before working. # stdlib escape() is inconsistent between Python 2 and Python 3. # In 3, html.escape() translates the single quote to ''' # In 2.6 and 2.7, cgi.escape() does not touch the single quote. # Preserve our tests and Kajiki behaviour across Python versions: return uval.replace('&', '&').replace('<', '<') \ .replace('>', '>').replace('"', '"') # .replace("'", ''')) # Above we do NOT escape the single quote; we don't need it because # all HTML attributes are double-quoted in our output. else: return uval _re_escape = re.compile(r'&|<|>|"') def _render_attrs(self, attrs, mode): if hasattr(attrs, 'items'): attrs = attrs.items() if attrs is not None: for k, v in sorted(attrs): if v is None: continue if mode.startswith('html') and k in HTML_EMPTY_ATTRS: yield ' ' + k.lower() else: yield ' %s="%s"' % (k, self._escape(v)) def _collect(self, it): result = [] for part in it: if part is None: continue result.append(str(part)) if result: return ''.join(result) else: return None @classmethod def annotate_lnotab(cls, py_to_tpl): for name, meth in cls.__methods__: meth.annotate_lnotab(cls.filename, py_to_tpl, dict(py_to_tpl)) def defined(self, name): return name in self._context def Template(ns): dct = {} methods = dct['__methods__'] = [] for name in dir(ns): value = getattr(ns, name) if getattr(value, 'exposed', False): methods.append((name, TplFunc(getattr(value, '__func__', value)))) return type(ns.__name__, (_Template,), dct) def from_ir(ir_node): py_lines = list(generate_python(ir_node)) py_text = '\n'.join(map(str, py_lines)) py_linenos = [] last_lineno = 0 for i, l in enumerate(py_lines): lno = max(last_lineno, l._lineno or 0) py_linenos.append((i + 1, lno)) last_lineno = lno dct = dict(kajiki=kajiki) try: exec(py_text, dct) except (SyntaxError, IndentationError): # pragma no cover for i, line in enumerate(py_text.splitlines()): print('%3d %s' % (i + 1, line)) raise tpl = dct['template'] tpl.base_globals = dct tpl.py_text = py_text tpl.filename = ir_node.filename tpl.annotate_lnotab(py_linenos) return tpl class TplFunc(object): def __init__(self, func, inst=None): self._func = func self._inst = inst self._bound_func = None def bind_instance(self, inst): return TplFunc(self._func, inst) def __repr__(self): # pragma no cover if self._inst: return '' % ( self._func.__name__, self._inst) else: return '' % (self._func.__name__) def __call__(self, *args, **kwargs): if self._bound_func is None: self._bound_func = self._bind_globals( self._inst.__globals__) return self._bound_func(*args, **kwargs) def _bind_globals(self, globals): '''Return a function which has the globals dict set to 'globals' and which flattens the result of self._func'. ''' func = types.FunctionType( self._func.__code__, globals, self._func.__name__, self._func.__defaults__, self._func.__closure__ ) return update_wrapper( lambda *a, **kw: flattener(func(*a, **kw)), func) def annotate_lnotab(self, filename, py_to_tpl, py_to_tpl_dct): if not py_to_tpl: return code = self._func.__code__ new_lnotab_numbers = [] for bc_off, py_lno in lnotab.lnotab_numbers( code.co_lnotab, code.co_firstlineno): tpl_lno = py_to_tpl_dct.get(py_lno, None) if tpl_lno is None: print('ERROR LOOKING UP LINE #%d' % py_lno) continue new_lnotab_numbers.append((bc_off, tpl_lno)) if not new_lnotab_numbers: return new_firstlineno = py_to_tpl_dct.get(code.co_firstlineno, 0) new_lnotab = lnotab.lnotab_string(new_lnotab_numbers, new_firstlineno) new_code = patch_code_file_lines( code, filename, new_firstlineno, new_lnotab) self._func.__code__ = new_code return if IS_PYTHON2: def patch_code_file_lines(code, filename, firstlineno, lnotab): return types.CodeType(code.co_argcount, code.co_nlocals, code.co_stacksize, code.co_flags, code.co_code, code.co_consts, code.co_names, code.co_varnames, filename.encode('utf-8'), code.co_name, firstlineno, lnotab, code.co_freevars, code.co_cellvars) else: def patch_code_file_lines(code, filename, firstlineno, lnotab): return types.CodeType(code.co_argcount, code.co_kwonlyargcount, code.co_nlocals, code.co_stacksize, code.co_flags, code.co_code, code.co_consts, code.co_names, code.co_varnames, filename, code.co_name, firstlineno, lnotab, code.co_freevars, code.co_cellvars) Kajiki-0.4.4/kajiki/tests/0000775000175000017500000000000012212721424015544 5ustar nandonando00000000000000Kajiki-0.4.4/kajiki/tests/test_ir.py0000775000175000017500000002211512175512112017573 0ustar nandonando00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) from unittest import TestCase, main import kajiki from kajiki import ir class TestBasic(TestCase): def setUp(self): self.tpl = ir.TemplateNode( defs=[ir.DefNode( '__main__()', ir.TextNode('Hello, '), ir.ExprNode('name'), ir.TextNode('\n'))]) def test(self): tpl = kajiki.template.from_ir(self.tpl) rsp = tpl(dict(name='Rick')).render() assert rsp == 'Hello, Rick\n', rsp class TestSwitch(TestCase): def setUp(self): self.tpl = ir.TemplateNode( defs=[ir.DefNode( '__main__()', ir.ForNode( 'i in range(2)', ir.ExprNode('i'), ir.TextNode(' is '), ir.SwitchNode( 'i % 2', ir.CaseNode( '0', ir.TextNode('even\n')), ir.ElseNode( ir.TextNode('odd\n')))))]) def test_basic(self): tpl = kajiki.template.from_ir(self.tpl) rsp = tpl(dict()).render() assert rsp == '0 is even\n1 is odd\n', rsp class TestFunction(TestCase): def setUp(self): self.tpl = ir.TemplateNode( defs=[ir.DefNode( 'evenness(n)', ir.IfNode( 'n % 2 == 0', ir.TextNode('even')), ir.ElseNode( ir.TextNode('odd'))), ir.DefNode( '__main__()', ir.ForNode( 'i in range(2)', ir.ExprNode('i'), ir.TextNode(' is '), ir.ExprNode('evenness(i)'), ir.TextNode('\n')))]) def test_basic(self): tpl = kajiki.template.from_ir(self.tpl) rsp = tpl(dict(name='Rick')).render() assert rsp == '0 is even\n1 is odd\n', rsp class TestCall(TestCase): def setUp(self): self.tpl = ir.TemplateNode( defs=[ir.DefNode( 'quote(caller, speaker)', ir.ForNode( 'i in range(2)', ir.TextNode('Quoth '), ir.ExprNode('speaker'), ir.TextNode(', "'), ir.ExprNode('caller(i)'), ir.TextNode('."\n'))), ir.DefNode( '__main__()', ir.CallNode( '$caller(n)', "quote($caller, 'the raven')", ir.TextNode('Nevermore '), ir.ExprNode('n')))]) def test_basic(self): tpl = kajiki.template.from_ir(self.tpl) rsp = tpl(dict(name='Rick')).render() assert ( rsp == 'Quoth the raven, "Nevermore 0."\n' 'Quoth the raven, "Nevermore 1."\n'), rsp class TestImport(TestCase): def setUp(self): lib = ir.TemplateNode( defs=[ir.DefNode( 'evenness(n)', ir.IfNode( 'n % 2 == 0', ir.TextNode('even')), ir.ElseNode( ir.TextNode('odd'))), ir.DefNode( 'half_evenness(n)', ir.TextNode(' half of '), ir.ExprNode('n'), ir.TextNode(' is '), ir.ExprNode('evenness(n/2)'))]) tpl = ir.TemplateNode( defs=[ir.DefNode( '__main__()', ir.ImportNode( 'lib.txt', 'simple_function'), ir.ForNode( 'i in range(4)', ir.ExprNode('i'), ir.TextNode(' is '), ir.ExprNode('simple_function.evenness(i)'), ir.ExprNode('simple_function.half_evenness(i)'), ir.TextNode('\n')))]) loader = kajiki.loader.MockLoader({ 'lib.txt': kajiki.template.from_ir(lib), 'tpl.txt': kajiki.template.from_ir(tpl)}) self.tpl = loader.import_('tpl.txt') def test_import(self): rsp = self.tpl(dict(name='Rick')).render() assert (rsp == '0 is even half of 0 is even\n' '1 is odd half of 1 is odd\n' '2 is even half of 2 is odd\n' '3 is odd half of 3 is odd\n'), rsp class TestInclude(TestCase): def setUp(self): hdr = ir.TemplateNode( defs=[ ir.DefNode( '__main__()', ir.TextNode('# header\n'))]) tpl = ir.TemplateNode( defs=[ ir.DefNode( '__main__()', ir.TextNode('a\n'), ir.IncludeNode('hdr.txt'), ir.TextNode('b\n'))]) loader = kajiki.loader.MockLoader({ 'hdr.txt': kajiki.template.from_ir(hdr), 'tpl.txt': kajiki.template.from_ir(tpl)}) self.tpl = loader.import_('tpl.txt') def test_include(self): rsp = self.tpl(dict(name='Rick')).render() assert rsp == 'a\n# header\nb\n', rsp class TestExtends(TestCase): def setUp(self): parent_tpl = ir.TemplateNode( defs=[ ir.DefNode( '__main__()', ir.ExprNode('header()'), ir.ExprNode('body()'), ir.ExprNode('footer()')), ir.DefNode( 'header()', ir.TextNode('# Header name='), ir.ExprNode('name'), ir.TextNode('\n')), ir.DefNode( 'body()', ir.TextNode('## Parent Body\n'), ir.TextNode('local.id() = '), ir.ExprNode('local.id()'), ir.TextNode('\n'), ir.TextNode('self.id() = '), ir.ExprNode('self.id()'), ir.TextNode('\n'), ir.TextNode('child.id() = '), ir.ExprNode('child.id()'), ir.TextNode('\n')), ir.DefNode( 'footer()', ir.TextNode('# Footer\n')), ir.DefNode( 'id()', ir.TextNode('parent'))]) mid_tpl = ir.TemplateNode( defs=[ ir.DefNode( '__main__()', ir.ExtendNode('parent.txt')), ir.DefNode( 'id()', ir.TextNode('mid'))]) child_tpl = ir.TemplateNode( defs=[ ir.DefNode( '__main__()', ir.ExtendNode('mid.txt')), ir.DefNode( 'body()', ir.TextNode('## Child Body\n'), ir.ExprNode('parent.body()')), ir.DefNode( 'id()', ir.TextNode('child'))]) loader = kajiki.loader.MockLoader({ 'parent.txt': kajiki.template.from_ir(parent_tpl), 'mid.txt': kajiki.template.from_ir(mid_tpl), 'child.txt': kajiki.template.from_ir(child_tpl)}) self.loader = loader self.tpl = loader.import_('child.txt') def test_extends(self): rsp = self.tpl(dict(name='Rick')).render() assert (rsp == '# Header name=Rick\n' '## Child Body\n' '## Parent Body\n' 'local.id() = parent\n' 'self.id() = child\n' 'child.id() = mid\n' '# Footer\n'), rsp class TestDynamicExtends(TestCase): def setUp(self): p0 = ir.TemplateNode( defs=[ ir.DefNode( '__main__()', ir.TextNode('Parent 0'))]) p1 = ir.TemplateNode( defs=[ ir.DefNode( '__main__()', ir.TextNode('Parent 1'))]) child = ir.TemplateNode( defs=[ ir.DefNode( '__main__()', ir.IfNode( 'p==0', ir.ExtendNode('parent0.txt')), ir.ElseNode( ir.ExtendNode('parent1.txt')))]) loader = kajiki.loader.MockLoader({ 'parent0.txt': kajiki.template.from_ir(p0), 'parent1.txt': kajiki.template.from_ir(p1), 'child.txt': kajiki.template.from_ir(child)}) self.loader = loader self.tpl = loader.import_('child.txt') def test_extends(self): rsp = self.tpl(dict(p=0)).render() assert rsp == 'Parent 0', rsp rsp = self.tpl(dict(p=1)).render() assert rsp == 'Parent 1', rsp if __name__ == '__main__': main() Kajiki-0.4.4/kajiki/tests/data/0000775000175000017500000000000012212721424016455 5ustar nandonando00000000000000Kajiki-0.4.4/kajiki/tests/data/simple.html0000664000175000017500000000030612161046640020636 0ustar nandonando00000000000000
${two()} ${three()} ${one()}
Kajiki-0.4.4/kajiki/tests/data/debug.html0000664000175000017500000000031112175512112020424 0ustar nandonando00000000000000
${two()} ${three()} ${one()}
Kajiki-0.4.4/kajiki/tests/data/__init__.py0000664000175000017500000000000012161046640020557 0ustar nandonando00000000000000Kajiki-0.4.4/kajiki/tests/data/debug.txt0000664000175000017500000000016212175512112020303 0ustar nandonando00000000000000%def one() ${two()} %end %def two() ${three()} %end %def three() %py raise ValueError('Test error') %end ${one()} Kajiki-0.4.4/kajiki/tests/test_runtime.py0000775000175000017500000001663712175512112020660 0ustar nandonando00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) from unittest import TestCase, main import kajiki class TestBasic(TestCase): def setUp(self): class tpl: @kajiki.expose def __main__(): yield 'Hello,' yield name yield '\n' self.tpl = kajiki.Template(tpl) def test_basic(self): rsp = self.tpl(dict(name='Rick')).render() assert rsp == 'Hello,Rick\n', rsp class TestSwitch(TestCase): def setUp(self): class tpl: @kajiki.expose def __main__(): for i in range(2): yield local.__kj__.escape(i) yield ' is ' local.__kj__.push_switch(i % 2) if local.__kj__.case(0): yield 'even\n' else: yield 'odd\n' self.tpl = kajiki.Template(tpl) def test_basic(self): rsp = self.tpl().render() assert rsp == '0 is even\n1 is odd\n', rsp class TestFunction(TestCase): def setUp(self): class tpl: @kajiki.expose def evenness(n): if n % 2 == 0: yield 'even' else: yield 'odd' @kajiki.expose def __main__(): for i in range(2): yield local.__kj__.escape(i) yield ' is ' yield evenness(i) yield '\n' self.tpl = kajiki.Template(tpl) def test_basic(self): rsp = self.tpl(dict(name='Rick')).render() assert rsp == '0 is even\n1 is odd\n', rsp class TestCall(TestCase): def setUp(self): class tpl: @kajiki.expose def quote(caller, speaker): for i in range(2): yield 'Quoth ' yield speaker yield ', "' yield caller(i) yield '."\n' @kajiki.expose def __main__(): @__kj__.flattener.decorate def _kj_lambda(n): yield 'Nevermore ' yield local.__kj__.escape(n) yield quote(_kj_lambda, 'the raven') del _kj_lambda self.tpl = kajiki.Template(tpl) def test_basic(self): rsp = self.tpl(dict(name='Rick')).render() assert ( rsp == 'Quoth the raven, "Nevermore 0."\n' 'Quoth the raven, "Nevermore 1."\n'), rsp class TestImport(TestCase): def setUp(self): class lib_undec: @kajiki.expose def evenness(n): if n % 2 == 0: yield 'even' else: yield 'odd' @kajiki.expose def half_evenness(n): yield ' half of ' yield local.__kj__.escape(n) yield ' is ' yield evenness(n / 2) lib = kajiki.Template(lib_undec) class tpl: @kajiki.expose def __main__(): simple_function = lib(dict(globals())) for i in range(4): yield local.__kj__.escape(i) yield ' is ' yield simple_function.evenness(i) yield simple_function.half_evenness(i) yield '\n' self.tpl = kajiki.Template(tpl) def test_import(self): rsp = self.tpl(dict(name='Rick')).render() assert (rsp == '0 is even half of 0 is even\n' '1 is odd half of 1 is odd\n' '2 is even half of 2 is odd\n' '3 is odd half of 3 is odd\n'), rsp class TestInclude(TestCase): def setUp(self): class hdr_undec: @kajiki.expose def __main__(): yield '# header\n' hdr = kajiki.Template(hdr_undec) class tpl_undec: @kajiki.expose def __main__(): yield 'a\n' yield hdr().__main__() yield 'b\n' tpl = kajiki.Template(tpl_undec) self.tpl = tpl def test_include(self): rsp = self.tpl(dict(name='Rick')).render() assert rsp == 'a\n# header\nb\n', rsp class TestExtends(TestCase): def setUp(_self): class parent_tpl_undec: @kajiki.expose def __main__(): yield header() yield body() yield footer() @kajiki.expose def header(): yield '# Header name=' yield name yield '\n' @kajiki.expose def body(): yield '## Parent Body\n' yield 'local.id() = ' yield local.id() yield '\n' yield 'self.id() = ' yield self.id() yield '\n' yield 'child.id() = ' yield child.id() yield '\n' @kajiki.expose def footer(): yield '# Footer' yield '\n' @kajiki.expose def id(): yield 'parent' parent_tpl = kajiki.Template(parent_tpl_undec) class mid_tpl_undec: @kajiki.expose def __main__(): yield local.__kj__.extend(parent_tpl).__main__() @kajiki.expose def id(): yield 'mid' mid_tpl = kajiki.Template(mid_tpl_undec) class child_tpl_undec: @kajiki.expose def __main__(): yield local.__kj__.extend(mid_tpl).__main__() @kajiki.expose def body(): yield '## Child Body\n' yield parent.body() @kajiki.expose def id(): yield 'child' child_tpl = kajiki.Template(child_tpl_undec) _self.parent_tpl = parent_tpl _self.child_tpl = child_tpl def test_extends(self): rsp = self.child_tpl(dict(name='Rick')).render() assert (rsp == '# Header name=Rick\n' '## Child Body\n' '## Parent Body\n' 'local.id() = parent\n' 'self.id() = child\n' 'child.id() = mid\n' '# Footer\n'), rsp class TestDynamicExtends(TestCase): def setUp(_self): class parent_0_undec: @kajiki.expose def __main__(): yield 'Parent 0' parent_0 = kajiki.Template(parent_0_undec) class parent_1_undec: @kajiki.expose def __main__(): yield 'Parent 1' parent_1 = kajiki.Template(parent_1_undec) class child_tpl: @kajiki.expose def __main__(): if p == 0: yield local.__kj__.extend(parent_0).__main__() else: yield local.__kj__.extend(parent_1).__main__() _self.child_tpl = kajiki.Template(child_tpl) def test_extends(self): rsp = self.child_tpl(dict(p=0)).render() assert rsp == 'Parent 0', rsp rsp = self.child_tpl(dict(p=1)).render() assert rsp == 'Parent 1', rsp if __name__ == '__main__': main() Kajiki-0.4.4/kajiki/tests/test_xml.py0000775000175000017500000004562312212720074017772 0ustar nandonando00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) import os import sys import traceback import xml.dom.minidom from unittest import TestCase, main from nine import chr, str import kajiki from kajiki import MockLoader, XMLTemplate, FileLoader, PackageLoader DATA = os.path.join(os.path.dirname(__file__), 'data') class TestParser(TestCase): def test_parser(self): doc = kajiki.xml_template._Parser('', '''
Hello, $name < > $x
''').parse() xml.dom.minidom.parseString(doc.toxml().encode('utf-8')) class TestExpand(TestCase): def test_expand(self): doc = kajiki.xml_template._Parser('', '''
Foo
''').parse() kajiki.xml_template.expand(doc) node = doc.childNodes[0] for tagname, attr in kajiki.markup_template.QDIRECTIVES: if node.tagName == 'div': node = node.childNodes[0] continue assert node.tagName == tagname, '%s != %s' % ( node.tagName, tagname) if attr: assert len(node.attributes) == 1 assert node.hasAttribute(attr) assert node.getAttribute(attr) == tagname.split(':')[-1] else: assert len(node.attributes) == 0 assert len(node.childNodes) == 1 node = node.childNodes[0] def perform(source, expected_output, context=dict(name='Rick'), mode='xml', is_fragment=True): tpl = XMLTemplate(source, mode=mode, is_fragment=is_fragment) try: rsp = tpl(context).render() assert isinstance(rsp, str), 'render() must return a unicode string.' assert rsp == expected_output, rsp except: print('\n' + tpl.py_text) raise else: return tpl class TestSimple(TestCase): def test_empty_attr(self): perform(source='', mode='html', expected_output='') def test_pre_whitespace(self): src = '
\nHey there.  \n\n    I am indented.\n' \
              '
' perform(src, src, mode='html') perform(src, src, mode='xml') def test_textarea_whitespace(self): src = '' perform(src, src, mode='html') perform(src, src, mode='xml') def test_script(self): 'Always close script tags, even in xml mode.' source = '' perform(source, output, mode='html') perform(source, output + '', mode='xml') def test_script_escaping(self): '''In HTML script and style tags are automatically CDATA; in XML they must be explicitly be made so. ''' script = 'if (1 < 2) { doc.write("

Offen bach

"); }\n' src = ''.format(script) perform(src, mode='html', expected_output=''.format(script)) perform(src, ''.format( script), mode='xml') def test_style_escaping(self): style = 'html > body { display: none; }\n' src = ''.format(style) perform(src, ''.format(style), mode='xml') perform(src, ''.format(style), mode='html') def test_script_variable(self): '''Interpolate variables inside ' perform(src, '', mode='xml') perform(src, '', mode='html') def test_escape_dollar(self): perform('
$$
', '
$
') def test_escape_dollar_followed_by_dollar(self): perform('
$$$
', '
$$
') def test_double_escape_dollar(self): perform('
$$$$
', '
$$
') def test_preserve_dollar_not_variable_brace(self): perform('
$(
', '
$(
') perform('
$.
', '
$.
') def test_expr_name(self): perform('
Hello, $name
', '
Hello, Rick
') def test_expr_braced(self): perform('
Hello, ${name}
', '
Hello, Rick
') def test_expr_brace_complex(self): perform("
Hello, ${{'name':name}['name']}
", '
Hello, Rick
') def test_jquery_call_is_not_expr(self): '''Ensure we handle '$(' as a text literal, since it cannot be a valid variable sequence. This simplifies, for example, templates containing inline scripts with jQuery calls which otherwise have to be written '$$(...' ''' js = "$(function () { alert('.ready()'); });" src = "
" + js + "
" out = "
" + js + "
" perform(src, out) def test_jquery_shortcut_is_not_expr(self): '''Ensure we handle '$.' as a text literal in script blocks''' js = "$.extend({}, {foo: 'bar'})" src = "
" + js + "
" out = "
" + js + "
" perform(src, out) def test_xml_entities(self): source = "
Cookies & Cream
" perform(source, source) def test_html_entities(self): source = "
Spam Spam < Spam > Spam
" output = '
SpamТ Spam < Spam > Spam
' assert chr(32) in output # normal space assert chr(160) in output # non breaking space perform(source, output) class TestSwitch(TestCase): def test_switch(self): perform('''
$i is even odd
''', '''
0 is even
1 is odd
''') class TestWith(TestCase): def test_with(self): perform('''
$a
$a
$a
''', '''
foo
5
foo
''') class TestFunction(TestCase): def test_function(self): perform('''
evenodd
$i is ${evenness(i)}
''', '''
0 is
even
1 is
odd
''') def test_empty_function(self): '''Do not crash if a function has no content.''' perform('
', '
') class TestCall(TestCase): def test_call(self): perform('''
  • Quoth $speaker, ${caller(i)}
Nevermore $n
''', '''
  • Quoth the raven, Nevermore 0
  • Quoth the raven, Nevermore 1
''') class TestImport(TestCase): def test_import(self): loader = MockLoader({ 'lib.html': XMLTemplate(source='''
evenodd half of $n is ${evenness(n/2)}
'''), 'tpl.html': XMLTemplate(source='''
  • $i is ${simple_function.evenness(i)} ${simple_function.half_evenness(i)}
''') }) tpl = loader.import_('tpl.html') rsp = tpl(dict(name='Rick')).render() assert rsp == '''
  • 0 is even half of 0 is even
  • 1 is odd half of 1 is odd
  • 2 is even half of 2 is odd
  • 3 is odd half of 3 is odd
''', rsp def test_import_auto(self): loader = MockLoader({ 'lib.html': XMLTemplate(source='''
evenodd half of $n is ${evenness(n/2)}
'''), 'tpl.html': XMLTemplate(source='''
  • $i is ${lib.evenness(i)} ${lib.half_evenness(i)}
''') }) tpl = loader.import_('tpl.html') rsp = tpl(dict(name='Rick')).render() assert rsp == '''
  • 0 is even half of 0 is even
  • 1 is odd half of 1 is odd
  • 2 is even half of 2 is odd
  • 3 is odd half of 3 is odd
''', rsp def test_include(self): '''Must NOT result in: NameError: global name 'name' is not defined''' loader = MockLoader({ 'included.html': XMLTemplate('

The included template must also ' 'access Kajiki globals and the template context: ' '${value_of("name")}

\n'), 'tpl.html': XMLTemplate('

This is the body

\n' '') }) tpl = loader.import_('tpl.html') rsp = tpl(dict(name='Rick')).render() assert ('

This is the body

\n' '

The included template must also access Kajiki globals and ' 'the template context: Rick

' == rsp) class TestExtends(TestCase): def test_basic(self): loader = MockLoader({ 'parent.html': XMLTemplate('''

Header name=$name

Footer
id() = ${id()} local.id() = ${local.id()} self.id() = ${self.id()} child.id() = ${child.id()}
parent ${header()} ${body()} ${footer()}
'''), 'mid.html': XMLTemplate('''mid'''), 'child.html': XMLTemplate('''child

Child Body

${parent.body()}
''')}) tpl = loader.import_('child.html') rsp = tpl(dict(name='Rick')).render() assert rsp == '''

Header name=Rick

Child Body

id() = child local.id() = parent self.id() = child child.id() = mid
Footer
''', rsp def test_dynamic(self): loader = MockLoader({ 'parent0.html': XMLTemplate('Parent 0'), 'parent1.html': XMLTemplate('Parent 1'), 'child.html': XMLTemplate('''
''') }) tpl = loader.import_('child.html') rsp = tpl(dict(p=0)).render() assert rsp == '
Parent 0
', rsp rsp = tpl(dict(p=1)).render() assert rsp == '
Parent 1
', rsp def test_block(self): loader = MockLoader({ 'parent.html': XMLTemplate('''
Hello, $name!Sincerely,
$name
${greet(to)}

It was good seeing you last Friday. Thanks for the gift!

${sign(from_)}
'''), 'child.html': XMLTemplate('''Dear $name:${parent_block()}

And don't forget you owe me money!

''')}) parent = loader.import_('parent.html') rsp = parent({'to': 'Mark', 'from_': 'Rick'}).render() assert rsp == '''
Hello, Mark!

It was good seeing you last Friday. Thanks for the gift!

Sincerely,
Rick
''', rsp child = loader.import_('child.html') rsp = child({'to': 'Mark', 'from_': 'Rick'}).render() assert rsp == '''
Dear Mark:

It was good seeing you last Friday. Thanks for the gift!

And don't forget you owe me money!

Sincerely,
Rick
''', rsp class TestClosure(TestCase): def test(self): perform('''
${x+y}${inner(x*2)}${add(5)}
''', '
15
') class TestPython(TestCase): def test_basic(self): perform('''
${os.path.join('a', 'b', 'c')}
''', '
a/b/c
') def test_indent(self): perform('''
${os.path.join('a','b','c')}
''', '
a/b/c
') def test_short(self): perform('''
${os.path.join('a', 'b', 'c')}
''', '
a/b/c
') def test_mod(self): perform('''
${os.path.join('a', 'b', 'c')}${test()}
''', '
a/b/c
') class TestComment(TestCase): def test_basic(self): perform('
' '
', '
') class TestAttributes(TestCase): def test_basic(self): perform('''
''', '
') def test_content(self): perform('''
''', '
foo
') def test_replace(self): perform('''
''', 'foo') def test_attrs(self): perform('
', '
') perform('''
''', '''
''') perform('
', '
') def test_strip(self): TPL = '

Header

' perform(TPL, '
Header
', context=dict(header=True)) perform(TPL, '

Header

', context=dict(header=False)) TPL = '''

It's...

''' perform(TPL, "
It's...
") def test_html_attrs(self): TPL = '' context0 = dict(checked=None) context1 = dict(checked=True) perform(TPL, '', context0, mode='xml') perform(TPL, '', context1, mode='xml') perform(TPL, '', context0, 'html') perform(TPL, '', context1, 'html') perform(TPL, '', context1, mode='html5', is_fragment=False) perform('\n' + TPL, '', context1, mode=None, is_fragment=False) def test_xml_namespaces(self): '''Namespaced attributes pass through.''' TPL = '

English text

' perform(TPL, TPL, mode='xml') perform(TPL, TPL[:-4], mode='html') def test_escape_attr_values(self): '''Escape static and dynamic attribute values.''' context = dict(url='https://domain.com/path?a=1&b=2') source = '''Link''' output = 'Link' perform(source, output, context, mode='html') perform(source, output, context, mode='xml') class TestDebug(TestCase): def test_debug(self): loader = FileLoader(path=os.path.join(os.path.dirname(__file__), 'data')) tpl = loader.import_('debug.html') try: tpl().render() assert False, 'Should have raised ValueError' except ValueError: exc_info = sys.exc_info() stack = traceback.extract_tb(exc_info[2]) # Verify we have stack trace entries in the template for fn, lno, func, line in stack: if fn.endswith('debug.html'): break else: assert False, 'Stacktrace is all python' class TestPackageLoader(TestCase): def test_pkg_loader(self): loader = PackageLoader() loader.import_('kajiki.tests.data.debug') class TestBuiltinFunctions(TestCase): def test_defined(self): perform('''
\
$albatross
\

$parrot

''', expected_output='

Bereft of life, it rests in peace

', context=dict(parrot='Bereft of life, it rests in peace')) def test_value_of(self): TPL = "

${value_of('albatross', 'Albatross!!!')}

" perform(TPL, expected_output="

It's

", context=dict(albatross="It's")) perform(TPL, expected_output="

Albatross!!!

") def test_literal(self): '''Escape by default; literal() marks as safe.''' context = dict(albatross="Albatross!!!") expected_output = "

Albatross!!!

" perform("

${literal(albatross)}

", expected_output, context) perform("

${Markup(albatross)}

", expected_output, context) perform("

$albatross

", "

<em>Albatross!!!</em>

", context) from kajiki.util import literal markup = '"&"' assert ''.join(list(literal(markup))) == markup if __name__ == '__main__': main() Kajiki-0.4.4/kajiki/tests/test_doctype.py0000664000175000017500000000310412175512112020622 0ustar nandonando00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) from unittest import TestCase, main from nine import str from kajiki.doctype import DocumentTypeDeclaration, extract_dtd XHTML1 = '' class TestDTD(TestCase): def test_dtd(self): dtd = DocumentTypeDeclaration.by_uri[''] assert dtd.name == 'html5' assert str(dtd) == '', str(dtd) assert dtd.rendering_mode == 'html5' dtd = DocumentTypeDeclaration.by_uri[None] assert dtd.name == 'xhtml5' assert str(dtd) == '', str(dtd) assert dtd.rendering_mode == 'xml' dtd = DocumentTypeDeclaration.by_uri[ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"] assert dtd.name == 'xhtml1transitional' assert str(dtd) == XHTML1 assert dtd.rendering_mode == 'xml' def test_extract_dtd(self): html = '
Test template
' markup = XHTML1 + html extracted, pos, rest = extract_dtd(markup) # The function being tested assert extracted == XHTML1 assert pos == 0 assert rest == html dtd = DocumentTypeDeclaration.matching(extracted) # Another function assert dtd is DocumentTypeDeclaration.by_uri[ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"] if __name__ == '__main__': main() Kajiki-0.4.4/kajiki/tests/test_text.py0000775000175000017500000002176512175512112020157 0ustar nandonando00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) import os import sys import traceback from unittest import TestCase, main from kajiki import MockLoader, FileLoader, TextTemplate class TestBasic(TestCase): def test_auto_escape(self): tpl = TextTemplate(source="${'

'}", autoescape=True) rsp = tpl().render() assert rsp == '<h1>', rsp def test_auto_escape_disable(self): tpl = TextTemplate(source="${literal('

')}") rsp = tpl().render() assert rsp == '

', rsp tpl = TextTemplate(source="${'

'}", autoescape=False) rsp = tpl().render() assert rsp == '

', rsp def test_expr_brace(self): tpl = TextTemplate(source='Hello, ${name}\n') rsp = tpl(dict(name='Rick')).render() assert rsp == 'Hello, Rick\n', rsp def test_expr_None(self): tpl = TextTemplate(source='Hello, ${name}\n') rsp = tpl(dict(name=None)).render() assert rsp == 'Hello, \n', rsp def test_expr_brace_complex(self): tpl = TextTemplate(source="Hello, ${{'name':name}['name']}\n") rsp = tpl(dict(name='Rick')).render() assert rsp == 'Hello, Rick\n', rsp def test_expr_name(self): tpl = TextTemplate(source='Hello, $name\n') rsp = tpl(dict(name='Rick')).render() assert rsp == 'Hello, Rick\n', rsp tpl = TextTemplate(source='Hello, $obj.name\n') class Empty: pass Empty.name = 'Rick' rsp = tpl(dict(obj=Empty)).render() assert rsp == 'Hello, Rick\n', rsp class TestSwitch(TestCase): def test_switch(self): tpl = TextTemplate('''%for i in range(2) $i is {%switch i % 2 %}{%case 0%}even\n{%else%}odd\n{%end%}\\ %end''') rsp = tpl(dict(name='Rick')).render() assert rsp == '0 is even\n1 is odd\n', rsp def test_ljust(self): tpl = TextTemplate(''' %for i in range(2) $i is {%switch i % 2 %}{%case 0%}even\n{%else%}odd\n{%end%}\\ %end''') rsp = tpl(dict(name='Rick')).render() assert rsp == '0 is even\n1 is odd\n', rsp tpl = TextTemplate(''' {%-for i in range(2)%}\\ $i is {%switch i % 2 %}{%case 0%}even{%else%}odd{%end%} {%-end%}''') rsp = tpl(dict(name='Rick')).render() assert rsp == '0 is even\n1 is odd\n', rsp def test_rstrip(self): tpl = TextTemplate(''' %for i in range(2) $i is {%switch i % 2 %}{%case 0-%} even\n{%else%}odd\n{%end%}\\ %end''') rsp = tpl(dict(name='Rick')).render() assert rsp == '0 is even\n1 is odd\n', rsp class TestFunction(TestCase): def test_function(self): tpl = TextTemplate('''%def evenness(n) {%if n % 2 == 0 %}even{%else%}odd{%end%}\\ %end %for i in range(2) $i is ${evenness(i)} %end ''') rsp = tpl(dict(name='Rick')).render() assert rsp == '0 is even\n1 is odd\n', rsp class TestCall(TestCase): def test_call(self): tpl = TextTemplate('''%def quote(caller, speaker) %for i in range(2) Quoth $speaker, "${caller(i)}." %end %end %call(n) quote(%caller ,'the raven') Nevermore $n\\ %end''') rsp = tpl(dict(name='Rick')).render() assert ( rsp == 'Quoth the raven, "Nevermore 0."\n' 'Quoth the raven, "Nevermore 1."\n'), rsp class TestImport(TestCase): def test_import_simple(self): lib = TextTemplate('''%def evenness(n) %if n % 2 == 0 even\\ %else odd\\ %end %end %def half_evenness(n) half of $n is ${evenness(n/2)}\\ %end''') tpl = TextTemplate('''%import "lib.txt" as simple_function %for i in range(4) $i is ${simple_function.evenness(i)}${simple_function.half_evenness(i)} %end''') loader = MockLoader({ 'lib.txt': lib, 'tpl.txt': tpl}) tpl = loader.import_('tpl.txt') rsp = tpl(dict(name='Rick')).render() assert (rsp == '0 is even half of 0 is even\n' '1 is odd half of 1 is odd\n' '2 is even half of 2 is odd\n' '3 is odd half of 3 is odd\n'), rsp def test_import_auto(self): lib = TextTemplate('''%def evenness(n) %if n % 2 == 0 even\\ %else odd\\ %end %end %def half_evenness(n) half of $n is ${evenness(n/2)}\\ %end''') tpl = TextTemplate('''%import "lib.txt" %for i in range(4) $i is ${lib.evenness(i)}${lib.half_evenness(i)} %end''') loader = MockLoader({ 'lib.txt': lib, 'tpl.txt': tpl}) tpl = loader.import_('tpl.txt') rsp = tpl(dict(name='Rick')).render() assert (rsp == '0 is even half of 0 is even\n' '1 is odd half of 1 is odd\n' '2 is even half of 2 is odd\n' '3 is odd half of 3 is odd\n'), rsp def test_include(self): loader = MockLoader({ 'hdr.txt': TextTemplate('# header\n'), 'tpl.txt': TextTemplate('''a %include "hdr.txt" b ''')}) tpl = loader.import_('tpl.txt') rsp = tpl(dict(name='Rick')).render() assert rsp == 'a\n# header\nb\n', rsp class TestExtends(TestCase): def test_basic(self): parent = TextTemplate(''' %def header() # Header name=$name %end %def footer() # Footer %end %def body() ## Parent Body id() = ${id()} local.id() = ${local.id()} self.id() = ${self.id()} child.id() = ${child.id()} %end %def id() parent\\ %end ${header()}${body()}${footer()}''') mid = TextTemplate('''%extends "parent.txt" %def id() mid\\ %end ''') child = TextTemplate('''%extends "mid.txt" %def id() child\\ %end %def body() ## Child Body ${parent.body()}\\ %end ''') loader = MockLoader({ 'parent.txt': parent, 'mid.txt': mid, 'child.txt': child}) tpl = loader.import_('child.txt') rsp = tpl(dict(name='Rick')).render() assert (rsp == '# Header name=Rick\n' '## Child Body\n' '## Parent Body\n' 'id() = child\n' 'local.id() = parent\n' 'self.id() = child\n' 'child.id() = mid\n' '# Footer\n'), rsp def test_dynamic(self): loader = MockLoader({ 'parent0.txt': TextTemplate('Parent 0'), 'parent1.txt': TextTemplate('Parent 1'), 'child.txt': TextTemplate('''%if p == 0 %extends "parent0.txt" %else %extends "parent1.txt" %end ''') }) tpl = loader.import_('child.txt') rsp = tpl(dict(p=0)).render() assert rsp == 'Parent 0', rsp rsp = tpl(dict(p=1)).render() assert rsp == 'Parent 1', rsp def test_block(self): loader = MockLoader({ 'parent.txt': TextTemplate('''%def greet(name) Hello, $name!\\ %end %def sign(name) Sincerely, $name\\ %end ${greet(to)} %block body It was good seeing you last Friday. Thanks for the gift! %end ${sign(from_)} '''), 'child.txt': TextTemplate('''%extends "parent.txt" %def greet(name) Dear $name:\\ %end %block body ${parent_block()}\\ And don't forget you owe me money! %end ''')}) child = loader.import_('child.txt') rsp = child({'to': 'Mark', 'from_': 'Rick'}).render() assert (rsp == '''Dear Mark: It was good seeing you last Friday. Thanks for the gift! And don't forget you owe me money! Sincerely, Rick '''), rsp class TestClosure(TestCase): def test(self): tpl = TextTemplate('''%def add(x) %def inner(y) ${x+y}\\ %end ${inner(x*2)}\\ %end ${add(5)} ''') rsp = tpl(dict(name='Rick')).render() assert rsp == '15\n', rsp class TestPython(TestCase): def test_basic(self): tpl = TextTemplate('''%py import os %end ${os.path.join('a','b','c')}''') rsp = tpl(dict(name='Rick')).render() assert rsp == 'a/b/c' def test_indent(self): tpl = TextTemplate('''%py import os import re %end ${os.path.join('a','b','c')}''') rsp = tpl(dict(name='Rick')).render() assert rsp == 'a/b/c' def test_short(self): tpl = TextTemplate('''%py import os ${os.path.join('a','b','c')}''') rsp = tpl(dict(name='Rick')).render() assert rsp == 'a/b/c' def test_mod(self): tpl = TextTemplate('''%py% import os %def test() ${os.path.join('a','b','c')}\\ %end ${test()}''') rsp = tpl(dict(name='Rick')).render() assert rsp == 'a/b/c' class TestDebug(TestCase): def test_debug(self): loader = FileLoader(path=os.path.join(os.path.dirname(__file__), 'data')) tpl = loader.import_('debug.txt') try: tpl().render() except ValueError: exc_info = sys.exc_info() stack = traceback.extract_tb(exc_info[2]) else: assert False, 'Should have raised ValueError' # Verify we have stack trace entries in the template for fn, lno, func, line in stack: if fn.endswith('debug.txt'): break else: assert False, 'Stacktrace is all python' if __name__ == '__main__': main() Kajiki-0.4.4/kajiki/tests/__init__.py0000664000175000017500000000020612175512112017653 0ustar nandonando00000000000000# -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) Kajiki-0.4.4/kajiki/doctype.py0000664000175000017500000001031612175512112016424 0ustar nandonando00000000000000# -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) import re from nine import str, nine, itervalues from nine.decorator import reify @nine class DocumentTypeDeclaration(object): '''Represents a http://en.wikipedia.org/wiki/Document_Type_Declaration''' def __init__(self, name, fpi='', uri='', rendering_mode='xml', root_element='html', kind='PUBLIC'): '''*fpi* is the Formal Public Identifier.''' self.name = name self.fpi = fpi self.uri = uri self.rendering_mode = rendering_mode self.root_element = root_element assert kind in ('PUBLIC', 'SYSTEM', ''), \ '*kind* can be either "PUBLIC", "SYSTEM", or empty.' self.kind = kind self._cached_str = None def __str__(self): if not self._cached_str: alist = ['' return self._cached_str @reify def regex(self): return re.compile(str(self).replace(' ', r'\s+').replace('.', r'\.') .replace('[', r'\[').replace(']', r'\]'), flags=re.IGNORECASE) by_uri = dict() # We store the public DTDs here. @classmethod def matching(cls, dtd_string): '''Looks up the known DTDs and returns the instance that matches the provided dtd_string. ''' for dtd in itervalues(cls.by_uri): if dtd.regex.match(dtd_string): return dtd else: return None REGEX = re.compile(r']+>') # This matches any DTD. # Build the public DTDs dictionary for dtd in ( DocumentTypeDeclaration('html5', kind='', rendering_mode='html5'), DocumentTypeDeclaration('xhtml5', kind='', uri=None), DocumentTypeDeclaration('xhtml1transitional', "-//W3C//DTD XHTML 1.0 Transitional//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"), DocumentTypeDeclaration('xhtml1strict', "-//W3C//DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"), DocumentTypeDeclaration('xhtml1rdfa', "-//W3C//DTD XHTML+RDFa 1.0//EN", "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd"), DocumentTypeDeclaration('xhtml11', "-//W3C//DTD XHTML 1.1//EN", "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"), DocumentTypeDeclaration('xhtml1frameset', "-//W3C//DTD XHTML 1.0 Frameset//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"), DocumentTypeDeclaration('xhtmlbasic11', "-//W3C//DTD XHTML Basic 1.1//EN", "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd"), DocumentTypeDeclaration('xhtmlmobile12', "-//WAPFORUM//DTD XHTML Mobile 1.2//EN", "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd"), DocumentTypeDeclaration('html4transitional', "-//W3C//DTD HTML 4.01 Transitional//EN", "http://www.w3.org/TR/html4/loose.dtd", rendering_mode='html'), DocumentTypeDeclaration('html4strict', "-//W3C//DTD HTML 4.01//EN", "http://www.w3.org/TR/html4/strict.dtd", rendering_mode='html'), DocumentTypeDeclaration('html4frameset', "-//W3C//DTD HTML 4.01 Frameset//EN", "http://www.w3.org/TR/html4/frameset.dtd", rendering_mode='html'), # html3='', # html2='', # xml='', ): DocumentTypeDeclaration.by_uri[dtd.uri] = dtd def extract_dtd(markup): '''Tries to find any DTD in the string *markup* and returns a tuple (dtd_string, position, markup_without_the_DTD). Note the first of these values might be an empty string. ''' match = DocumentTypeDeclaration.REGEX.search(markup) if not match: return '', 0, markup found = match.group() return found, match.start(), markup.replace(found, '', 1) Kajiki-0.4.4/kajiki/version.py0000664000175000017500000000026012212721417016441 0ustar nandonando00000000000000# -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) __version__ = '0.4' __release__ = '0.4.4' Kajiki-0.4.4/kajiki/xml_template.py0000664000175000017500000004452112212720074017455 0ustar nandonando00000000000000# -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, unicode_literals) import re from codecs import open from xml import sax from xml.dom import minidom as dom from nine import IS_PYTHON2, basestring, str, iteritems if IS_PYTHON2: from cStringIO import StringIO as BytesIO else: from io import BytesIO from . import ir from . import template from .ddict import defaultdict from .doctype import DocumentTypeDeclaration, extract_dtd from .entities import html5, unescape from .html_utils import (HTML_OPTIONAL_END_TAGS, HTML_REQUIRED_END_TAGS, HTML_CDATA_TAGS) from .markup_template import QDIRECTIVES, QDIRECTIVES_DICT impl = dom.getDOMImplementation(' ') def XMLTemplate(source=None, filename=None, mode=None, is_fragment=False, encoding='utf-8'): if source is None: with open(filename, encoding=encoding) as f: source = f.read() # source is a unicode string if filename is None: filename = '' doc = _Parser(filename, source).parse() expand(doc) compiler = _Compiler(filename, doc, mode=mode, is_fragment=is_fragment) ir_ = compiler.compile() return template.from_ir(ir_) def annotate(gen): def inner(self, node, *args, **kwargs): for x in gen(self, node, *args, **kwargs): self._anno(node, x) yield x return inner class _Compiler(object): def __init__(self, filename, doc, mode=None, is_fragment=False): self.filename = filename self.doc = doc self.is_fragment = is_fragment self.functions = defaultdict(list) self.functions['__main__()'] = [] self.function_lnos = {} self.mod_py = [] self.in_def = False self.is_child = False # The rendering mode is either specified in the *mode* argument, # or inferred from the DTD: self._dtd = DocumentTypeDeclaration.matching(self.doc._dtd) if mode: self.mode = mode elif self._dtd: self.mode = self._dtd.rendering_mode else: # The template might contain an unknown DTD self.mode = 'xml' # by default def compile(self): body = list(self._compile_node(self.doc.firstChild)) # Never emit doctypes on fragments if not self.is_fragment and not self.is_child: if self.doc._dtd: dtd = self.doc._dtd elif self.mode == 'html5': dtd = '' else: dtd = None if dtd: dtd = ir.TextNode(dtd) dtd.filename = self.filename dtd.lineno = 1 body.insert(0, dtd) self.functions['__main__()'] = body defs = [] for k, v in iteritems(self.functions): node = ir.DefNode(k, *v) node.lineno = self.function_lnos.get(k) defs.append(node) node = ir.TemplateNode(self.mod_py, defs) node.filename = self.filename node.lineno = 0 return node def _anno(self, dom_node, ir_node): if ir_node.lineno: return ir_node.filename = self.filename ir_node.lineno = dom_node.lineno def _compile_node(self, node): if isinstance(node, dom.Comment): return self._compile_comment(node) elif isinstance(node, dom.Text): return self._compile_text(node) elif isinstance(node, dom.ProcessingInstruction): return self._compile_pi(node) elif node.tagName.startswith('py:'): # Handle directives compiler = getattr( self, '_compile_%s' % node.tagName.split(':')[-1], self._compile_xml) return compiler(node) else: return self._compile_xml(node) @annotate def _compile_xml(self, node): content = attrs = guard = None if node.hasAttribute('py:strip'): guard = node.getAttribute('py:strip') if guard == '': # py:strip="" means yes, do strip the tag guard = 'False' else: guard = 'not (%s)' % guard node.removeAttribute('py:strip') yield ir.TextNode('<%s' % node.tagName, guard) for k, v in sorted(node.attributes.items()): tc = _TextCompiler(self.filename, v, node.lineno, ir.TextNode, in_html_attr=True) v = list(tc) if k == 'py:content': content = node.getAttribute('py:content') continue elif k == 'py:attrs': attrs = node.getAttribute('py:attrs') continue yield ir.AttrNode(k, v, guard, self.mode) if attrs: yield ir.AttrsNode(attrs, guard, self.mode) if content: yield ir.TextNode('>', guard) yield ir.ExprNode(content) yield ir.TextNode('' % node.tagName, guard) else: if node.childNodes: yield ir.TextNode('>', guard) if node.tagName in HTML_CDATA_TAGS: # Special behaviour for This is not necessary when you are writing HTML because HTML defines that the content of ``