From a1469a96ed660970cd2f3bb660292da60f3be839 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Thu, 8 Dec 2022 13:04:44 +0800 Subject: [PATCH 01/30] feat(web/problem): add 2600 to difficulties --- web/app/models/UOJProblem.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/app/models/UOJProblem.php b/web/app/models/UOJProblem.php index e200a14..d520f93 100644 --- a/web/app/models/UOJProblem.php +++ b/web/app/models/UOJProblem.php @@ -22,6 +22,7 @@ class UOJProblem { 2300, 2400, 2500, + 2600, 2700, 2900, 3100, @@ -43,9 +44,10 @@ class UOJProblem { 2300 => '#ff8000', 2400 => '#ff8000', 2500 => '#ff8000', + 2600 => '#ff0000', 2700 => '#ff0000', 2900 => '#ff0000', - 3100 => '#ff0000', + 3100 => '#aa0000', 3300 => '#aa0000', 3500 => '#aa0000', ]; From 382fecac89ff5402825f407b62eeeb4e2fac3a3a Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Fri, 9 Dec 2022 20:27:54 +0800 Subject: [PATCH 02/30] Revert "chore(web): disable custom test" This reverts commit 248a924df7b8ba8f75a14ad900432bd4b6b174dd. --- web/app/controllers/problem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app/controllers/problem.php b/web/app/controllers/problem.php index 8ce857b..ef90fed 100644 --- a/web/app/controllers/problem.php +++ b/web/app/controllers/problem.php @@ -100,7 +100,7 @@ if (UOJContest::cur()) { $submission_requirement = UOJProblem::cur()->getSubmissionRequirement(); $custom_test_requirement = UOJProblem::cur()->getCustomTestRequirement(); -$custom_test_enabled = false; // $custom_test_requirement && $pre_submit_check_ret === true; +$custom_test_enabled = $custom_test_requirement && $pre_submit_check_ret === true; function handleUpload($zip_file_name, $content, $tot_size) { global $is_participating; From 4e149d376f3390b02353e0a333f4c8736c430794 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Fri, 23 Dec 2022 21:25:05 +0800 Subject: [PATCH 03/30] chore(web): move mathjax3 --- web/app/views/page-header.php | 2 +- .../MathJax => js/mathjax3}/a11y/assistive-mml.js | 0 web/{lib/MathJax => js/mathjax3}/a11y/complexity.js | 0 web/{lib/MathJax => js/mathjax3}/a11y/explorer.js | 0 .../MathJax => js/mathjax3}/a11y/semantic-enrich.js | 0 web/{lib/MathJax => js/mathjax3}/a11y/sre.js | 0 .../MathJax => js/mathjax3}/adaptors/liteDOM.js | 0 web/{lib/MathJax => js/mathjax3}/core.js | 0 web/{lib/MathJax => js/mathjax3}/input/asciimath.js | 0 web/{lib/MathJax => js/mathjax3}/input/mml.js | 0 .../MathJax => js/mathjax3}/input/mml/entities.js | 0 .../mathjax3}/input/mml/extensions/mml3.js | 0 .../mathjax3}/input/mml/extensions/mml3.sef.json | 0 web/{lib/MathJax => js/mathjax3}/input/tex-base.js | 0 web/{lib/MathJax => js/mathjax3}/input/tex-full.js | 0 web/{lib/MathJax => js/mathjax3}/input/tex.js | 0 .../mathjax3}/input/tex/extensions/action.js | 0 .../mathjax3}/input/tex/extensions/all-packages.js | 0 .../mathjax3}/input/tex/extensions/ams.js | 0 .../mathjax3}/input/tex/extensions/amscd.js | 0 .../mathjax3}/input/tex/extensions/autoload.js | 0 .../mathjax3}/input/tex/extensions/bbox.js | 0 .../mathjax3}/input/tex/extensions/boldsymbol.js | 0 .../mathjax3}/input/tex/extensions/braket.js | 0 .../mathjax3}/input/tex/extensions/bussproofs.js | 0 .../mathjax3}/input/tex/extensions/cancel.js | 0 .../mathjax3}/input/tex/extensions/cases.js | 0 .../mathjax3}/input/tex/extensions/centernot.js | 0 .../mathjax3}/input/tex/extensions/color.js | 0 .../mathjax3}/input/tex/extensions/colortbl.js | 0 .../mathjax3}/input/tex/extensions/colorv2.js | 0 .../mathjax3}/input/tex/extensions/configmacros.js | 0 .../mathjax3}/input/tex/extensions/empheq.js | 0 .../mathjax3}/input/tex/extensions/enclose.js | 0 .../mathjax3}/input/tex/extensions/extpfeil.js | 0 .../mathjax3}/input/tex/extensions/gensymb.js | 0 .../mathjax3}/input/tex/extensions/html.js | 0 .../mathjax3}/input/tex/extensions/mathtools.js | 0 .../mathjax3}/input/tex/extensions/mhchem.js | 0 .../mathjax3}/input/tex/extensions/newcommand.js | 0 .../mathjax3}/input/tex/extensions/noerrors.js | 0 .../mathjax3}/input/tex/extensions/noundefined.js | 0 .../mathjax3}/input/tex/extensions/physics.js | 0 .../mathjax3}/input/tex/extensions/require.js | 0 .../mathjax3}/input/tex/extensions/setoptions.js | 0 .../mathjax3}/input/tex/extensions/tagformat.js | 0 .../mathjax3}/input/tex/extensions/textcomp.js | 0 .../mathjax3}/input/tex/extensions/textmacros.js | 0 .../mathjax3}/input/tex/extensions/unicode.js | 0 .../mathjax3}/input/tex/extensions/upgreek.js | 0 .../mathjax3}/input/tex/extensions/verb.js | 0 web/{lib/MathJax => js/mathjax3}/latest.js | 0 web/{lib/MathJax => js/mathjax3}/loader.js | 0 web/{lib/MathJax => js/mathjax3}/mml-chtml.js | 0 web/{lib/MathJax => js/mathjax3}/mml-svg.js | 0 web/{lib/MathJax => js/mathjax3}/node-main.js | 0 web/{lib/MathJax => js/mathjax3}/output/chtml.js | 0 .../mathjax3}/output/chtml/fonts/tex.js | 0 .../chtml/fonts/woff-v2/MathJax_AMS-Regular.woff | Bin .../fonts/woff-v2/MathJax_Calligraphic-Bold.woff | Bin .../fonts/woff-v2/MathJax_Calligraphic-Regular.woff | Bin .../chtml/fonts/woff-v2/MathJax_Fraktur-Bold.woff | Bin .../fonts/woff-v2/MathJax_Fraktur-Regular.woff | Bin .../chtml/fonts/woff-v2/MathJax_Main-Bold.woff | Bin .../chtml/fonts/woff-v2/MathJax_Main-Italic.woff | Bin .../chtml/fonts/woff-v2/MathJax_Main-Regular.woff | Bin .../fonts/woff-v2/MathJax_Math-BoldItalic.woff | Bin .../chtml/fonts/woff-v2/MathJax_Math-Italic.woff | Bin .../chtml/fonts/woff-v2/MathJax_Math-Regular.woff | Bin .../chtml/fonts/woff-v2/MathJax_SansSerif-Bold.woff | Bin .../fonts/woff-v2/MathJax_SansSerif-Italic.woff | Bin .../fonts/woff-v2/MathJax_SansSerif-Regular.woff | Bin .../chtml/fonts/woff-v2/MathJax_Script-Regular.woff | Bin .../chtml/fonts/woff-v2/MathJax_Size1-Regular.woff | Bin .../chtml/fonts/woff-v2/MathJax_Size2-Regular.woff | Bin .../chtml/fonts/woff-v2/MathJax_Size3-Regular.woff | Bin .../chtml/fonts/woff-v2/MathJax_Size4-Regular.woff | Bin .../fonts/woff-v2/MathJax_Typewriter-Regular.woff | Bin .../chtml/fonts/woff-v2/MathJax_Vector-Bold.woff | Bin .../chtml/fonts/woff-v2/MathJax_Vector-Regular.woff | Bin .../output/chtml/fonts/woff-v2/MathJax_Zero.woff | Bin web/{lib/MathJax => js/mathjax3}/output/svg.js | 0 .../MathJax => js/mathjax3}/output/svg/fonts/tex.js | 0 .../MathJax => js/mathjax3}/sre/mathmaps/base.json | 0 .../MathJax => js/mathjax3}/sre/mathmaps/ca.json | 0 .../MathJax => js/mathjax3}/sre/mathmaps/da.json | 0 .../MathJax => js/mathjax3}/sre/mathmaps/de.json | 0 .../MathJax => js/mathjax3}/sre/mathmaps/en.json | 0 .../MathJax => js/mathjax3}/sre/mathmaps/es.json | 0 .../MathJax => js/mathjax3}/sre/mathmaps/fr.json | 0 .../MathJax => js/mathjax3}/sre/mathmaps/hi.json | 0 .../MathJax => js/mathjax3}/sre/mathmaps/it.json | 0 .../MathJax => js/mathjax3}/sre/mathmaps/nb.json | 0 .../mathjax3}/sre/mathmaps/nemeth.json | 0 .../MathJax => js/mathjax3}/sre/mathmaps/nn.json | 0 .../MathJax => js/mathjax3}/sre/mathmaps/sv.json | 0 web/{lib/MathJax => js/mathjax3}/startup.js | 0 .../mathjax3}/tex-chtml-full-speech.js | 0 web/{lib/MathJax => js/mathjax3}/tex-chtml-full.js | 0 web/{lib/MathJax => js/mathjax3}/tex-chtml.js | 0 web/{lib/MathJax => js/mathjax3}/tex-mml-chtml.js | 0 web/{lib/MathJax => js/mathjax3}/tex-mml-svg.js | 0 web/{lib/MathJax => js/mathjax3}/tex-svg-full.js | 0 web/{lib/MathJax => js/mathjax3}/tex-svg.js | 0 web/{lib/MathJax => js/mathjax3}/ui/lazy.js | 0 web/{lib/MathJax => js/mathjax3}/ui/menu.js | 0 web/{lib/MathJax => js/mathjax3}/ui/safe.js | 0 web/lib/.gitkeep | 0 108 files changed, 1 insertion(+), 1 deletion(-) rename web/{lib/MathJax => js/mathjax3}/a11y/assistive-mml.js (100%) rename web/{lib/MathJax => js/mathjax3}/a11y/complexity.js (100%) rename web/{lib/MathJax => js/mathjax3}/a11y/explorer.js (100%) rename web/{lib/MathJax => js/mathjax3}/a11y/semantic-enrich.js (100%) rename web/{lib/MathJax => js/mathjax3}/a11y/sre.js (100%) rename web/{lib/MathJax => js/mathjax3}/adaptors/liteDOM.js (100%) rename web/{lib/MathJax => js/mathjax3}/core.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/asciimath.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/mml.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/mml/entities.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/mml/extensions/mml3.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/mml/extensions/mml3.sef.json (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex-base.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex-full.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/action.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/all-packages.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/ams.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/amscd.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/autoload.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/bbox.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/boldsymbol.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/braket.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/bussproofs.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/cancel.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/cases.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/centernot.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/color.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/colortbl.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/colorv2.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/configmacros.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/empheq.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/enclose.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/extpfeil.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/gensymb.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/html.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/mathtools.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/mhchem.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/newcommand.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/noerrors.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/noundefined.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/physics.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/require.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/setoptions.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/tagformat.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/textcomp.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/textmacros.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/unicode.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/upgreek.js (100%) rename web/{lib/MathJax => js/mathjax3}/input/tex/extensions/verb.js (100%) rename web/{lib/MathJax => js/mathjax3}/latest.js (100%) rename web/{lib/MathJax => js/mathjax3}/loader.js (100%) rename web/{lib/MathJax => js/mathjax3}/mml-chtml.js (100%) rename web/{lib/MathJax => js/mathjax3}/mml-svg.js (100%) rename web/{lib/MathJax => js/mathjax3}/node-main.js (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml.js (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/tex.js (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_AMS-Regular.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Bold.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Regular.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Fraktur-Bold.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Fraktur-Regular.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Main-Bold.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Main-Italic.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Main-Regular.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Math-BoldItalic.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Math-Italic.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Math-Regular.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_SansSerif-Bold.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_SansSerif-Italic.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_SansSerif-Regular.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Script-Regular.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Size1-Regular.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Size2-Regular.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Size3-Regular.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Size4-Regular.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Typewriter-Regular.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Vector-Bold.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Vector-Regular.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/chtml/fonts/woff-v2/MathJax_Zero.woff (100%) rename web/{lib/MathJax => js/mathjax3}/output/svg.js (100%) rename web/{lib/MathJax => js/mathjax3}/output/svg/fonts/tex.js (100%) rename web/{lib/MathJax => js/mathjax3}/sre/mathmaps/base.json (100%) rename web/{lib/MathJax => js/mathjax3}/sre/mathmaps/ca.json (100%) rename web/{lib/MathJax => js/mathjax3}/sre/mathmaps/da.json (100%) rename web/{lib/MathJax => js/mathjax3}/sre/mathmaps/de.json (100%) rename web/{lib/MathJax => js/mathjax3}/sre/mathmaps/en.json (100%) rename web/{lib/MathJax => js/mathjax3}/sre/mathmaps/es.json (100%) rename web/{lib/MathJax => js/mathjax3}/sre/mathmaps/fr.json (100%) rename web/{lib/MathJax => js/mathjax3}/sre/mathmaps/hi.json (100%) rename web/{lib/MathJax => js/mathjax3}/sre/mathmaps/it.json (100%) rename web/{lib/MathJax => js/mathjax3}/sre/mathmaps/nb.json (100%) rename web/{lib/MathJax => js/mathjax3}/sre/mathmaps/nemeth.json (100%) rename web/{lib/MathJax => js/mathjax3}/sre/mathmaps/nn.json (100%) rename web/{lib/MathJax => js/mathjax3}/sre/mathmaps/sv.json (100%) rename web/{lib/MathJax => js/mathjax3}/startup.js (100%) rename web/{lib/MathJax => js/mathjax3}/tex-chtml-full-speech.js (100%) rename web/{lib/MathJax => js/mathjax3}/tex-chtml-full.js (100%) rename web/{lib/MathJax => js/mathjax3}/tex-chtml.js (100%) rename web/{lib/MathJax => js/mathjax3}/tex-mml-chtml.js (100%) rename web/{lib/MathJax => js/mathjax3}/tex-mml-svg.js (100%) rename web/{lib/MathJax => js/mathjax3}/tex-svg-full.js (100%) rename web/{lib/MathJax => js/mathjax3}/tex-svg.js (100%) rename web/{lib/MathJax => js/mathjax3}/ui/lazy.js (100%) rename web/{lib/MathJax => js/mathjax3}/ui/menu.js (100%) rename web/{lib/MathJax => js/mathjax3}/ui/safe.js (100%) delete mode 100644 web/lib/.gitkeep diff --git a/web/app/views/page-header.php b/web/app/views/page-header.php index 3ca855c..46f3424 100644 --- a/web/app/views/page-header.php +++ b/web/app/views/page-header.php @@ -175,7 +175,7 @@ if (!isset($ShowPageHeader)) { } }; - + diff --git a/web/lib/MathJax/a11y/assistive-mml.js b/web/js/mathjax3/a11y/assistive-mml.js similarity index 100% rename from web/lib/MathJax/a11y/assistive-mml.js rename to web/js/mathjax3/a11y/assistive-mml.js diff --git a/web/lib/MathJax/a11y/complexity.js b/web/js/mathjax3/a11y/complexity.js similarity index 100% rename from web/lib/MathJax/a11y/complexity.js rename to web/js/mathjax3/a11y/complexity.js diff --git a/web/lib/MathJax/a11y/explorer.js b/web/js/mathjax3/a11y/explorer.js similarity index 100% rename from web/lib/MathJax/a11y/explorer.js rename to web/js/mathjax3/a11y/explorer.js diff --git a/web/lib/MathJax/a11y/semantic-enrich.js b/web/js/mathjax3/a11y/semantic-enrich.js similarity index 100% rename from web/lib/MathJax/a11y/semantic-enrich.js rename to web/js/mathjax3/a11y/semantic-enrich.js diff --git a/web/lib/MathJax/a11y/sre.js b/web/js/mathjax3/a11y/sre.js similarity index 100% rename from web/lib/MathJax/a11y/sre.js rename to web/js/mathjax3/a11y/sre.js diff --git a/web/lib/MathJax/adaptors/liteDOM.js b/web/js/mathjax3/adaptors/liteDOM.js similarity index 100% rename from web/lib/MathJax/adaptors/liteDOM.js rename to web/js/mathjax3/adaptors/liteDOM.js diff --git a/web/lib/MathJax/core.js b/web/js/mathjax3/core.js similarity index 100% rename from web/lib/MathJax/core.js rename to web/js/mathjax3/core.js diff --git a/web/lib/MathJax/input/asciimath.js b/web/js/mathjax3/input/asciimath.js similarity index 100% rename from web/lib/MathJax/input/asciimath.js rename to web/js/mathjax3/input/asciimath.js diff --git a/web/lib/MathJax/input/mml.js b/web/js/mathjax3/input/mml.js similarity index 100% rename from web/lib/MathJax/input/mml.js rename to web/js/mathjax3/input/mml.js diff --git a/web/lib/MathJax/input/mml/entities.js b/web/js/mathjax3/input/mml/entities.js similarity index 100% rename from web/lib/MathJax/input/mml/entities.js rename to web/js/mathjax3/input/mml/entities.js diff --git a/web/lib/MathJax/input/mml/extensions/mml3.js b/web/js/mathjax3/input/mml/extensions/mml3.js similarity index 100% rename from web/lib/MathJax/input/mml/extensions/mml3.js rename to web/js/mathjax3/input/mml/extensions/mml3.js diff --git a/web/lib/MathJax/input/mml/extensions/mml3.sef.json b/web/js/mathjax3/input/mml/extensions/mml3.sef.json similarity index 100% rename from web/lib/MathJax/input/mml/extensions/mml3.sef.json rename to web/js/mathjax3/input/mml/extensions/mml3.sef.json diff --git a/web/lib/MathJax/input/tex-base.js b/web/js/mathjax3/input/tex-base.js similarity index 100% rename from web/lib/MathJax/input/tex-base.js rename to web/js/mathjax3/input/tex-base.js diff --git a/web/lib/MathJax/input/tex-full.js b/web/js/mathjax3/input/tex-full.js similarity index 100% rename from web/lib/MathJax/input/tex-full.js rename to web/js/mathjax3/input/tex-full.js diff --git a/web/lib/MathJax/input/tex.js b/web/js/mathjax3/input/tex.js similarity index 100% rename from web/lib/MathJax/input/tex.js rename to web/js/mathjax3/input/tex.js diff --git a/web/lib/MathJax/input/tex/extensions/action.js b/web/js/mathjax3/input/tex/extensions/action.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/action.js rename to web/js/mathjax3/input/tex/extensions/action.js diff --git a/web/lib/MathJax/input/tex/extensions/all-packages.js b/web/js/mathjax3/input/tex/extensions/all-packages.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/all-packages.js rename to web/js/mathjax3/input/tex/extensions/all-packages.js diff --git a/web/lib/MathJax/input/tex/extensions/ams.js b/web/js/mathjax3/input/tex/extensions/ams.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/ams.js rename to web/js/mathjax3/input/tex/extensions/ams.js diff --git a/web/lib/MathJax/input/tex/extensions/amscd.js b/web/js/mathjax3/input/tex/extensions/amscd.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/amscd.js rename to web/js/mathjax3/input/tex/extensions/amscd.js diff --git a/web/lib/MathJax/input/tex/extensions/autoload.js b/web/js/mathjax3/input/tex/extensions/autoload.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/autoload.js rename to web/js/mathjax3/input/tex/extensions/autoload.js diff --git a/web/lib/MathJax/input/tex/extensions/bbox.js b/web/js/mathjax3/input/tex/extensions/bbox.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/bbox.js rename to web/js/mathjax3/input/tex/extensions/bbox.js diff --git a/web/lib/MathJax/input/tex/extensions/boldsymbol.js b/web/js/mathjax3/input/tex/extensions/boldsymbol.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/boldsymbol.js rename to web/js/mathjax3/input/tex/extensions/boldsymbol.js diff --git a/web/lib/MathJax/input/tex/extensions/braket.js b/web/js/mathjax3/input/tex/extensions/braket.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/braket.js rename to web/js/mathjax3/input/tex/extensions/braket.js diff --git a/web/lib/MathJax/input/tex/extensions/bussproofs.js b/web/js/mathjax3/input/tex/extensions/bussproofs.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/bussproofs.js rename to web/js/mathjax3/input/tex/extensions/bussproofs.js diff --git a/web/lib/MathJax/input/tex/extensions/cancel.js b/web/js/mathjax3/input/tex/extensions/cancel.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/cancel.js rename to web/js/mathjax3/input/tex/extensions/cancel.js diff --git a/web/lib/MathJax/input/tex/extensions/cases.js b/web/js/mathjax3/input/tex/extensions/cases.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/cases.js rename to web/js/mathjax3/input/tex/extensions/cases.js diff --git a/web/lib/MathJax/input/tex/extensions/centernot.js b/web/js/mathjax3/input/tex/extensions/centernot.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/centernot.js rename to web/js/mathjax3/input/tex/extensions/centernot.js diff --git a/web/lib/MathJax/input/tex/extensions/color.js b/web/js/mathjax3/input/tex/extensions/color.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/color.js rename to web/js/mathjax3/input/tex/extensions/color.js diff --git a/web/lib/MathJax/input/tex/extensions/colortbl.js b/web/js/mathjax3/input/tex/extensions/colortbl.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/colortbl.js rename to web/js/mathjax3/input/tex/extensions/colortbl.js diff --git a/web/lib/MathJax/input/tex/extensions/colorv2.js b/web/js/mathjax3/input/tex/extensions/colorv2.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/colorv2.js rename to web/js/mathjax3/input/tex/extensions/colorv2.js diff --git a/web/lib/MathJax/input/tex/extensions/configmacros.js b/web/js/mathjax3/input/tex/extensions/configmacros.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/configmacros.js rename to web/js/mathjax3/input/tex/extensions/configmacros.js diff --git a/web/lib/MathJax/input/tex/extensions/empheq.js b/web/js/mathjax3/input/tex/extensions/empheq.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/empheq.js rename to web/js/mathjax3/input/tex/extensions/empheq.js diff --git a/web/lib/MathJax/input/tex/extensions/enclose.js b/web/js/mathjax3/input/tex/extensions/enclose.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/enclose.js rename to web/js/mathjax3/input/tex/extensions/enclose.js diff --git a/web/lib/MathJax/input/tex/extensions/extpfeil.js b/web/js/mathjax3/input/tex/extensions/extpfeil.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/extpfeil.js rename to web/js/mathjax3/input/tex/extensions/extpfeil.js diff --git a/web/lib/MathJax/input/tex/extensions/gensymb.js b/web/js/mathjax3/input/tex/extensions/gensymb.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/gensymb.js rename to web/js/mathjax3/input/tex/extensions/gensymb.js diff --git a/web/lib/MathJax/input/tex/extensions/html.js b/web/js/mathjax3/input/tex/extensions/html.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/html.js rename to web/js/mathjax3/input/tex/extensions/html.js diff --git a/web/lib/MathJax/input/tex/extensions/mathtools.js b/web/js/mathjax3/input/tex/extensions/mathtools.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/mathtools.js rename to web/js/mathjax3/input/tex/extensions/mathtools.js diff --git a/web/lib/MathJax/input/tex/extensions/mhchem.js b/web/js/mathjax3/input/tex/extensions/mhchem.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/mhchem.js rename to web/js/mathjax3/input/tex/extensions/mhchem.js diff --git a/web/lib/MathJax/input/tex/extensions/newcommand.js b/web/js/mathjax3/input/tex/extensions/newcommand.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/newcommand.js rename to web/js/mathjax3/input/tex/extensions/newcommand.js diff --git a/web/lib/MathJax/input/tex/extensions/noerrors.js b/web/js/mathjax3/input/tex/extensions/noerrors.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/noerrors.js rename to web/js/mathjax3/input/tex/extensions/noerrors.js diff --git a/web/lib/MathJax/input/tex/extensions/noundefined.js b/web/js/mathjax3/input/tex/extensions/noundefined.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/noundefined.js rename to web/js/mathjax3/input/tex/extensions/noundefined.js diff --git a/web/lib/MathJax/input/tex/extensions/physics.js b/web/js/mathjax3/input/tex/extensions/physics.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/physics.js rename to web/js/mathjax3/input/tex/extensions/physics.js diff --git a/web/lib/MathJax/input/tex/extensions/require.js b/web/js/mathjax3/input/tex/extensions/require.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/require.js rename to web/js/mathjax3/input/tex/extensions/require.js diff --git a/web/lib/MathJax/input/tex/extensions/setoptions.js b/web/js/mathjax3/input/tex/extensions/setoptions.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/setoptions.js rename to web/js/mathjax3/input/tex/extensions/setoptions.js diff --git a/web/lib/MathJax/input/tex/extensions/tagformat.js b/web/js/mathjax3/input/tex/extensions/tagformat.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/tagformat.js rename to web/js/mathjax3/input/tex/extensions/tagformat.js diff --git a/web/lib/MathJax/input/tex/extensions/textcomp.js b/web/js/mathjax3/input/tex/extensions/textcomp.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/textcomp.js rename to web/js/mathjax3/input/tex/extensions/textcomp.js diff --git a/web/lib/MathJax/input/tex/extensions/textmacros.js b/web/js/mathjax3/input/tex/extensions/textmacros.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/textmacros.js rename to web/js/mathjax3/input/tex/extensions/textmacros.js diff --git a/web/lib/MathJax/input/tex/extensions/unicode.js b/web/js/mathjax3/input/tex/extensions/unicode.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/unicode.js rename to web/js/mathjax3/input/tex/extensions/unicode.js diff --git a/web/lib/MathJax/input/tex/extensions/upgreek.js b/web/js/mathjax3/input/tex/extensions/upgreek.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/upgreek.js rename to web/js/mathjax3/input/tex/extensions/upgreek.js diff --git a/web/lib/MathJax/input/tex/extensions/verb.js b/web/js/mathjax3/input/tex/extensions/verb.js similarity index 100% rename from web/lib/MathJax/input/tex/extensions/verb.js rename to web/js/mathjax3/input/tex/extensions/verb.js diff --git a/web/lib/MathJax/latest.js b/web/js/mathjax3/latest.js similarity index 100% rename from web/lib/MathJax/latest.js rename to web/js/mathjax3/latest.js diff --git a/web/lib/MathJax/loader.js b/web/js/mathjax3/loader.js similarity index 100% rename from web/lib/MathJax/loader.js rename to web/js/mathjax3/loader.js diff --git a/web/lib/MathJax/mml-chtml.js b/web/js/mathjax3/mml-chtml.js similarity index 100% rename from web/lib/MathJax/mml-chtml.js rename to web/js/mathjax3/mml-chtml.js diff --git a/web/lib/MathJax/mml-svg.js b/web/js/mathjax3/mml-svg.js similarity index 100% rename from web/lib/MathJax/mml-svg.js rename to web/js/mathjax3/mml-svg.js diff --git a/web/lib/MathJax/node-main.js b/web/js/mathjax3/node-main.js similarity index 100% rename from web/lib/MathJax/node-main.js rename to web/js/mathjax3/node-main.js diff --git a/web/lib/MathJax/output/chtml.js b/web/js/mathjax3/output/chtml.js similarity index 100% rename from web/lib/MathJax/output/chtml.js rename to web/js/mathjax3/output/chtml.js diff --git a/web/lib/MathJax/output/chtml/fonts/tex.js b/web/js/mathjax3/output/chtml/fonts/tex.js similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/tex.js rename to web/js/mathjax3/output/chtml/fonts/tex.js diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_AMS-Regular.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_AMS-Regular.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_AMS-Regular.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_AMS-Regular.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Bold.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Bold.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Bold.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Bold.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Regular.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Regular.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Regular.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Regular.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Fraktur-Bold.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Fraktur-Bold.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Fraktur-Bold.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Fraktur-Bold.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Fraktur-Regular.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Fraktur-Regular.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Fraktur-Regular.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Fraktur-Regular.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Main-Bold.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Main-Bold.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Main-Bold.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Main-Bold.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Main-Italic.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Main-Italic.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Main-Italic.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Main-Italic.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Main-Regular.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Main-Regular.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Main-Regular.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Main-Regular.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Math-BoldItalic.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Math-BoldItalic.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Math-BoldItalic.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Math-BoldItalic.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Math-Italic.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Math-Italic.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Math-Italic.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Math-Italic.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Math-Regular.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Math-Regular.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Math-Regular.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Math-Regular.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_SansSerif-Bold.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_SansSerif-Bold.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_SansSerif-Bold.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_SansSerif-Bold.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_SansSerif-Italic.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_SansSerif-Italic.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_SansSerif-Italic.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_SansSerif-Italic.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_SansSerif-Regular.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_SansSerif-Regular.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_SansSerif-Regular.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_SansSerif-Regular.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Script-Regular.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Script-Regular.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Script-Regular.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Script-Regular.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Size1-Regular.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Size1-Regular.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Size1-Regular.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Size1-Regular.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Size2-Regular.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Size2-Regular.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Size2-Regular.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Size2-Regular.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Size3-Regular.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Size3-Regular.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Size3-Regular.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Size3-Regular.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Size4-Regular.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Size4-Regular.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Size4-Regular.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Size4-Regular.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Typewriter-Regular.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Typewriter-Regular.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Typewriter-Regular.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Typewriter-Regular.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Vector-Bold.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Vector-Bold.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Vector-Bold.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Vector-Bold.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Vector-Regular.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Vector-Regular.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Vector-Regular.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Vector-Regular.woff diff --git a/web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Zero.woff b/web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Zero.woff similarity index 100% rename from web/lib/MathJax/output/chtml/fonts/woff-v2/MathJax_Zero.woff rename to web/js/mathjax3/output/chtml/fonts/woff-v2/MathJax_Zero.woff diff --git a/web/lib/MathJax/output/svg.js b/web/js/mathjax3/output/svg.js similarity index 100% rename from web/lib/MathJax/output/svg.js rename to web/js/mathjax3/output/svg.js diff --git a/web/lib/MathJax/output/svg/fonts/tex.js b/web/js/mathjax3/output/svg/fonts/tex.js similarity index 100% rename from web/lib/MathJax/output/svg/fonts/tex.js rename to web/js/mathjax3/output/svg/fonts/tex.js diff --git a/web/lib/MathJax/sre/mathmaps/base.json b/web/js/mathjax3/sre/mathmaps/base.json similarity index 100% rename from web/lib/MathJax/sre/mathmaps/base.json rename to web/js/mathjax3/sre/mathmaps/base.json diff --git a/web/lib/MathJax/sre/mathmaps/ca.json b/web/js/mathjax3/sre/mathmaps/ca.json similarity index 100% rename from web/lib/MathJax/sre/mathmaps/ca.json rename to web/js/mathjax3/sre/mathmaps/ca.json diff --git a/web/lib/MathJax/sre/mathmaps/da.json b/web/js/mathjax3/sre/mathmaps/da.json similarity index 100% rename from web/lib/MathJax/sre/mathmaps/da.json rename to web/js/mathjax3/sre/mathmaps/da.json diff --git a/web/lib/MathJax/sre/mathmaps/de.json b/web/js/mathjax3/sre/mathmaps/de.json similarity index 100% rename from web/lib/MathJax/sre/mathmaps/de.json rename to web/js/mathjax3/sre/mathmaps/de.json diff --git a/web/lib/MathJax/sre/mathmaps/en.json b/web/js/mathjax3/sre/mathmaps/en.json similarity index 100% rename from web/lib/MathJax/sre/mathmaps/en.json rename to web/js/mathjax3/sre/mathmaps/en.json diff --git a/web/lib/MathJax/sre/mathmaps/es.json b/web/js/mathjax3/sre/mathmaps/es.json similarity index 100% rename from web/lib/MathJax/sre/mathmaps/es.json rename to web/js/mathjax3/sre/mathmaps/es.json diff --git a/web/lib/MathJax/sre/mathmaps/fr.json b/web/js/mathjax3/sre/mathmaps/fr.json similarity index 100% rename from web/lib/MathJax/sre/mathmaps/fr.json rename to web/js/mathjax3/sre/mathmaps/fr.json diff --git a/web/lib/MathJax/sre/mathmaps/hi.json b/web/js/mathjax3/sre/mathmaps/hi.json similarity index 100% rename from web/lib/MathJax/sre/mathmaps/hi.json rename to web/js/mathjax3/sre/mathmaps/hi.json diff --git a/web/lib/MathJax/sre/mathmaps/it.json b/web/js/mathjax3/sre/mathmaps/it.json similarity index 100% rename from web/lib/MathJax/sre/mathmaps/it.json rename to web/js/mathjax3/sre/mathmaps/it.json diff --git a/web/lib/MathJax/sre/mathmaps/nb.json b/web/js/mathjax3/sre/mathmaps/nb.json similarity index 100% rename from web/lib/MathJax/sre/mathmaps/nb.json rename to web/js/mathjax3/sre/mathmaps/nb.json diff --git a/web/lib/MathJax/sre/mathmaps/nemeth.json b/web/js/mathjax3/sre/mathmaps/nemeth.json similarity index 100% rename from web/lib/MathJax/sre/mathmaps/nemeth.json rename to web/js/mathjax3/sre/mathmaps/nemeth.json diff --git a/web/lib/MathJax/sre/mathmaps/nn.json b/web/js/mathjax3/sre/mathmaps/nn.json similarity index 100% rename from web/lib/MathJax/sre/mathmaps/nn.json rename to web/js/mathjax3/sre/mathmaps/nn.json diff --git a/web/lib/MathJax/sre/mathmaps/sv.json b/web/js/mathjax3/sre/mathmaps/sv.json similarity index 100% rename from web/lib/MathJax/sre/mathmaps/sv.json rename to web/js/mathjax3/sre/mathmaps/sv.json diff --git a/web/lib/MathJax/startup.js b/web/js/mathjax3/startup.js similarity index 100% rename from web/lib/MathJax/startup.js rename to web/js/mathjax3/startup.js diff --git a/web/lib/MathJax/tex-chtml-full-speech.js b/web/js/mathjax3/tex-chtml-full-speech.js similarity index 100% rename from web/lib/MathJax/tex-chtml-full-speech.js rename to web/js/mathjax3/tex-chtml-full-speech.js diff --git a/web/lib/MathJax/tex-chtml-full.js b/web/js/mathjax3/tex-chtml-full.js similarity index 100% rename from web/lib/MathJax/tex-chtml-full.js rename to web/js/mathjax3/tex-chtml-full.js diff --git a/web/lib/MathJax/tex-chtml.js b/web/js/mathjax3/tex-chtml.js similarity index 100% rename from web/lib/MathJax/tex-chtml.js rename to web/js/mathjax3/tex-chtml.js diff --git a/web/lib/MathJax/tex-mml-chtml.js b/web/js/mathjax3/tex-mml-chtml.js similarity index 100% rename from web/lib/MathJax/tex-mml-chtml.js rename to web/js/mathjax3/tex-mml-chtml.js diff --git a/web/lib/MathJax/tex-mml-svg.js b/web/js/mathjax3/tex-mml-svg.js similarity index 100% rename from web/lib/MathJax/tex-mml-svg.js rename to web/js/mathjax3/tex-mml-svg.js diff --git a/web/lib/MathJax/tex-svg-full.js b/web/js/mathjax3/tex-svg-full.js similarity index 100% rename from web/lib/MathJax/tex-svg-full.js rename to web/js/mathjax3/tex-svg-full.js diff --git a/web/lib/MathJax/tex-svg.js b/web/js/mathjax3/tex-svg.js similarity index 100% rename from web/lib/MathJax/tex-svg.js rename to web/js/mathjax3/tex-svg.js diff --git a/web/lib/MathJax/ui/lazy.js b/web/js/mathjax3/ui/lazy.js similarity index 100% rename from web/lib/MathJax/ui/lazy.js rename to web/js/mathjax3/ui/lazy.js diff --git a/web/lib/MathJax/ui/menu.js b/web/js/mathjax3/ui/menu.js similarity index 100% rename from web/lib/MathJax/ui/menu.js rename to web/js/mathjax3/ui/menu.js diff --git a/web/lib/MathJax/ui/safe.js b/web/js/mathjax3/ui/safe.js similarity index 100% rename from web/lib/MathJax/ui/safe.js rename to web/js/mathjax3/ui/safe.js diff --git a/web/lib/.gitkeep b/web/lib/.gitkeep deleted file mode 100644 index e69de29..0000000 From f3cf970aadf250089c3ebdc6d37d90363873d424 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Fri, 23 Dec 2022 21:29:05 +0800 Subject: [PATCH 04/30] fix(db): upgrades table default value --- db/app_uoj233.sql | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/db/app_uoj233.sql b/db/app_uoj233.sql index 9fb0e3a..12b362a 100644 --- a/db/app_uoj233.sql +++ b/db/app_uoj233.sql @@ -979,6 +979,17 @@ CREATE TABLE `upgrades` ( LOCK TABLES `upgrades` WRITE; /*!40000 ALTER TABLE `upgrades` DISABLE KEYS */; +INSERT INTO `upgrades` (`name`, `status`, `updated_at`) VALUES + ('3_parsedown', 'up', now()), + ('4_image_hosting', 'up', now()), + ('6_user_info_v2', 'up', now()), + ('8_group_v2', 'up', now()), + ('9_list_v2', 'up', now()), + ('14_sync_from_uoj.ac', 'up', now()), + ('16_list_v3', 'up', now()), + ('18_user_permissions', 'up', now()), + ('20_problem_difficulty', 'up', now()), + ('21_problem_difficulty', 'up', now()); /*!40000 ALTER TABLE `upgrades` ENABLE KEYS */; UNLOCK TABLES; From 35eb4c170c899a5e79e2be8dfe3d1098353cbfcd Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Fri, 23 Dec 2022 21:41:46 +0800 Subject: [PATCH 05/30] chore(web): translate more strings --- web/app/controllers/add_contest.php | 11 +++++----- web/app/controllers/problem.php | 32 +++++++++++++++++++++-------- web/app/locale/contests/en.php | 1 + web/app/locale/contests/zh-cn.php | 1 + web/app/locale/problems/en.php | 3 +++ web/app/locale/problems/zh-cn.php | 3 +++ 6 files changed, 38 insertions(+), 13 deletions(-) diff --git a/web/app/controllers/add_contest.php b/web/app/controllers/add_contest.php index 72b7776..75dfd82 100644 --- a/web/app/controllers/add_contest.php +++ b/web/app/controllers/add_contest.php @@ -9,7 +9,7 @@ $time_form = new UOJBs4Form('time'); $time_form->addVInput( 'name', 'text', - '比赛标题', + UOJLocale::get('contests::new contest'), 'New Contest', function ($name, &$vdata) { if ($name == '') { @@ -35,7 +35,7 @@ $time_form->addVInput( $time_form->addVInput( 'start_time', 'text', - '开始时间', + UOJLocale::get('contests::start time'), date("Y-m-d H:i:s"), function ($str, &$vdata) { try { @@ -75,7 +75,7 @@ $time_form->handle = function (&$vdata) { $time_form->succ_href = "/contests"; $time_form->runAtServer(); ?> - +
@@ -83,12 +83,13 @@ $time_form->runAtServer();
-

添加比赛

+

+ +

printHTML(); ?>
-
diff --git a/web/app/controllers/problem.php b/web/app/controllers/problem.php index ef90fed..cf6678c 100644 --- a/web/app/controllers/problem.php +++ b/web/app/controllers/problem.php @@ -385,16 +385,26 @@ if (UOJContest::cur()) {
diff --git a/web/app/locale/contests/en.php b/web/app/locale/contests/en.php index 8421782..da44fcb 100644 --- a/web/app/locale/contests/en.php +++ b/web/app/locale/contests/en.php @@ -1,5 +1,6 @@ 'New Contest', 'current or upcoming contests' => 'Current or upcoming contests', 'ended contests' => 'Ended contests', 'back to the contest' => 'Back to the contest', diff --git a/web/app/locale/contests/zh-cn.php b/web/app/locale/contests/zh-cn.php index e09aad0..6adefb6 100644 --- a/web/app/locale/contests/zh-cn.php +++ b/web/app/locale/contests/zh-cn.php @@ -1,5 +1,6 @@ '新建比赛', 'current or upcoming contests' => '正在进行或即将到来的比赛', 'ended contests' => '已结束的比赛', 'back to the contest' => '返回比赛', diff --git a/web/app/locale/problems/en.php b/web/app/locale/problems/en.php index 9522bc4..a7c1884 100644 --- a/web/app/locale/problems/en.php +++ b/web/app/locale/problems/en.php @@ -52,4 +52,7 @@ return [ 'hacks to me' => 'Hacks to me', 'difficulty' => 'Difficulty', 'show difficulty' => 'Show difficulty', + 'tags' => 'Tags', + 'historical score' => 'Historical Score', + 'uploader' => 'Uploader', ]; diff --git a/web/app/locale/problems/zh-cn.php b/web/app/locale/problems/zh-cn.php index 797ed51..580882f 100644 --- a/web/app/locale/problems/zh-cn.php +++ b/web/app/locale/problems/zh-cn.php @@ -52,4 +52,7 @@ return [ 'hacks to me' => '我的被Hack记录', 'difficulty' => '难度', 'show difficulty' => '显示难度', + 'tags' => '标签', + 'historical score' => '历史分数', + 'uploader' => '上传者', ]; From 10ccb2681564fe3668d671f006a20ae8fbc11396 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sun, 25 Dec 2022 09:35:52 +0800 Subject: [PATCH 06/30] chore(web/problem/submit): set default size limit to 100KB --- web/app/libs/uoj-form-lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app/libs/uoj-form-lib.php b/web/app/libs/uoj-form-lib.php index 1e03485..620da94 100644 --- a/web/app/libs/uoj-form-lib.php +++ b/web/app/libs/uoj-form-lib.php @@ -735,7 +735,7 @@ function newSubmissionForm($form_name, $requirement, $zip_file_name_gen, $handle $stat = $zip_file->statName($req['file_name']); if ($req['type'] == 'source code') { - $max_size = isset($req['size']) ? (int)$req['size'] : 50; + $max_size = isset($req['size']) ? (int)$req['size'] : 100; if ($stat['size'] > $max_size * 1024) { $zip_file->close(); unlink(UOJContext::storagePath() . $zip_file_name); From 781d1183badd8287c4c8582dc2e2954cddbcb8bf Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Tue, 27 Dec 2022 11:23:44 +0800 Subject: [PATCH 07/30] chore(web/contest/problem): hide tags and difficulty in contest --- web/app/controllers/problem.php | 74 +++++++++++++++++---------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/web/app/controllers/problem.php b/web/app/controllers/problem.php index cf6678c..d9ef9c6 100644 --- a/web/app/controllers/problem.php +++ b/web/app/controllers/problem.php @@ -392,48 +392,50 @@ if (UOJContest::cur()) { getUploaderLink() ?> -
  • - - - - - getDifficultyHTML() ?> - -
  • - + progress() >= CONTEST_FINISHED) : ?>
  • - + - UOJProblem::info('id'), "submitter" => Auth::id()]]) ?> + + getDifficultyHTML() ?> + +
  • + +
  • + + + + UOJProblem::info('id'), "submitter" => Auth::id()]]) ?> - - - + + + +
  • + +
  • + + + + + + + + + + + + + queryTags() as $tag) : ?> + 'uoj-problem-tag'], + HTML::tag('span', ['class' => 'badge bg-secondary'], HTML::escape($tag)) + ) ?> + +
  • -
  • - - - - - - - - - - - - - queryTags() as $tag) : ?> - 'uoj-problem-tag'], - HTML::tag('span', ['class' => 'badge bg-secondary'], HTML::escape($tag)) - ) ?> - - -
  • From 17fbb2c910360dd00325547e455e7087a6619d74 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sun, 8 Jan 2023 13:57:39 +0800 Subject: [PATCH 08/30] refactor(web/html2markdown): use turndown --- web/app/controllers/app/html2markdown.php | 105 ++ .../{ => app}/image_hosting/get_image.php | 0 .../controllers/app/image_hosting/index.php | 490 +++++++++ web/app/controllers/html2markdown.php | 46 - web/app/route.php | 6 +- web/js/h2m.js | 5 - web/js/turndown-plugin-gfm.js | 166 +++ web/js/turndown.js | 974 ++++++++++++++++++ 8 files changed, 1738 insertions(+), 54 deletions(-) create mode 100644 web/app/controllers/app/html2markdown.php rename web/app/controllers/{ => app}/image_hosting/get_image.php (100%) create mode 100644 web/app/controllers/app/image_hosting/index.php delete mode 100644 web/app/controllers/html2markdown.php delete mode 100644 web/js/h2m.js create mode 100644 web/js/turndown-plugin-gfm.js create mode 100644 web/js/turndown.js diff --git a/web/app/controllers/app/html2markdown.php b/web/app/controllers/app/html2markdown.php new file mode 100644 index 0000000..5cb76d1 --- /dev/null +++ b/web/app/controllers/app/html2markdown.php @@ -0,0 +1,105 @@ + + + + +

    + +

    + + + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    + +
    + + + + + + + diff --git a/web/app/controllers/image_hosting/get_image.php b/web/app/controllers/app/image_hosting/get_image.php similarity index 100% rename from web/app/controllers/image_hosting/get_image.php rename to web/app/controllers/app/image_hosting/get_image.php diff --git a/web/app/controllers/app/image_hosting/index.php b/web/app/controllers/app/image_hosting/index.php new file mode 100644 index 0000000..c6c60dd --- /dev/null +++ b/web/app/controllers/app/image_hosting/index.php @@ -0,0 +1,490 @@ + Auth::id(), + ], +]); +$count = DB::selectCount([ + "select count(*)", + "from users_images", + "where", [ + "uploader" => Auth::id(), + ], +]); + +function throwError($msg) { + dieWithJsonData(['status' => 'error', 'message' => $msg]); +} + +$allowedTypes = [IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_WEBP]; +if ($_POST['image_upload_file_submit'] == 'submit') { + if (!crsf_check()) { + throwError('expired'); + } + + if (!isset($_SESSION['phrase']) || !PhraseBuilder::comparePhrases($_SESSION['phrase'], $_POST['captcha'])) { + throwError("bad_captcha"); + } + + if ($_FILES["image_upload_file"]["error"] > 0) { + throwError($_FILES["image_upload_file"]["error"]); + } + + if ($_FILES["image_upload_file"]["size"] > 5242880) { // 5 MB + throwError('too_large'); + } + + if ($used + $_FILES["image_upload_file"]["size"] > $limit) { + throwError('storage_limit_exceeded'); + } + + $size = getimagesize($_FILES['image_upload_file']['tmp_name']); + + if (!$size || !in_array($size[2], $allowedTypes)) { + throwError('not_a_image'); + } + + list($width, $height, $type) = $size; + $hash = hash_file("sha256", $_FILES['image_upload_file']['tmp_name']) . Auth::id(); + $scale = ceil($width / 600.0); + + $watermark_text = UOJConfig::$data['profile']['oj-name-short']; + if (isSuperUser(Auth::user()) && $_POST['watermark'] == 'no_watermark') { + $watermark_text = ""; + $hash .= "__no_watermark"; + } elseif ($_POST['watermark'] == 'site_shortname_and_username') { + $watermark_text .= ' @' . Auth::id(); + $hash .= "__id"; + } + + $existing_image = DB::selectFirst("SELECT * FROM users_images WHERE `hash` = '$hash'"); + + if ($existing_image) { + dieWithJsonData(['status' => 'success', 'path' => $existing_image['path']]); + } + + $image = new Imagick($_FILES["image_upload_file"]["tmp_name"]); + $draw = new ImagickDraw(); + $draw->setFont(UOJContext::documentRoot() . '/fonts/roboto-mono/RobotoMono-Bold.ttf'); + $draw->setFontSize($scale * 14); + $draw->setGravity(Imagick::GRAVITY_SOUTHEAST); + $draw->setFillColor("rgba(100,100,100,0.5)"); + $image->annotateImage($draw, 15, 10, 0, $watermark_text); + $draw->setFillColor("rgba(255,255,255,0.65)"); + $image->annotateImage($draw, 15 + $scale, 10 + $scale, 0, $watermark_text); + $image->setImageFormat('png'); + $image->writeImage(); + + if (($size = filesize($_FILES["image_upload_file"]["tmp_name"])) > 5242880) { // 5 MB + throwError('too_large'); + } + + $filename = uojRandAvaiableFileName('/image_hosting/', 10, '.png'); + if (!move_uploaded_file($_FILES["image_upload_file"]["tmp_name"], UOJContext::storagePath() . $filename)) { + throwError('unknown error'); + } + + DB::insert([ + "insert into users_images", + DB::bracketed_fields(["path", "uploader", "width", "height", "upload_time", "size", "hash"]), + "values", DB::tuple([ + $filename, + Auth::id(), + $width, + $height, + DB::now(), + $_FILES["image_upload_file"]["size"], + $hash, + ]), + ]); + + dieWithJsonData(['status' => 'success', 'path' => $filename]); +} elseif ($_POST['image_delete_submit'] == 'submit') { + crsf_defend(); + + $id = $_POST['image_delete_id']; + if (!validateUInt($id)) { + becomeMsgPage('ID 不合法。返回'); + } else { + $result = DB::selectFirst("SELECT * from users_images WHERE id = $id"); + if (!$result) { + becomeMsgPage('图片不存在。返回'); + } else { + unlink(UOJContext::storagePath() . $result['path']); + DB::delete("DELETE FROM users_images WHERE id = $id"); + + header("Location: " . UOJContext::requestURI()); + die(); + } + } +} +?> + + + + + +

    + +

    + +
    +
    +
    +
    + + 点击此处选择图片 +
    + + +
    +

    水印

    + +
    + + +
    + +
    + + +
    +
    + + +
    +
    +
    +

    上传须知

    +
      +
    • 上传的图片必须符合法律与社会道德;
    • +
    • 图床仅供 S2OJ 站内使用,校外用户无法查看;
    • +
    • 图片上传后会被自动转码为 PNG 格式;
    • +
    • 在合适的地方插入图片即可引用。
    • +
    +

    更多信息可以查看 使用文档

    +
    +
    +

    使用统计

    +
    + 已用空间 + MB / MB +
    +
    + 上传总数 + +
    +
    +
    +
    +
    +
    + +
    + + + 40, + 'col_names' => ['*'], + 'table_name' => 'users_images', + 'cond' => "uploader = '{$myUser['username']}'", + 'tail' => 'order by upload_time desc', +]; +$pag = new Paginator($pag_config); +?> + +

    + 我的图片 +

    + +
    + get() as $idx => $row) : ?> +
    +
    + + +
    +
    + +
    + +isEmpty()) : ?> +
    + +
    + + +
    + pagination() ?> +
    + +
    + +
    + + + + diff --git a/web/app/controllers/html2markdown.php b/web/app/controllers/html2markdown.php deleted file mode 100644 index 4206260..0000000 --- a/web/app/controllers/html2markdown.php +++ /dev/null @@ -1,46 +0,0 @@ - - - - -

    - -

    - - - -
    -
    -
    -
    - -
    -
    - -
    -
    -
    - -
    - - - - - - diff --git a/web/app/route.php b/web/app/route.php index b90f26c..1f11278a 100644 --- a/web/app/route.php +++ b/web/app/route.php @@ -92,9 +92,9 @@ Route::group( Route::any('/click-zan', '/click_zan.php'); // Apps - Route::any('/image_hosting', '/image_hosting/index.php'); - Route::get('/image_hosting/{image_name}.png', '/image_hosting/get_image.php'); - Route::any('/html2markdown', '/html2markdown.php'); + Route::any('/image_hosting', '/app/image_hosting/index.php'); + Route::get('/image_hosting/{image_name}.png', '/app/image_hosting/get_image.php'); + Route::any('/html2markdown', '/app/html2markdown.php'); } ); diff --git a/web/js/h2m.js b/web/js/h2m.js deleted file mode 100644 index d6393ed..0000000 --- a/web/js/h2m.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! h2m v0.7.0 (forked version) | https://github.com/renbaoshuo/h2m */ - -!function t(e,r,n){function i(s,a){if(!r[s]){if(!e[s]){var c="function"==typeof require&&require;if(!a&&c)return c(s,!0);if(o)return o(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var l=r[s]={exports:{}};e[s][0].call(l.exports,(function(t){return i(e[s][1][t]||t)}),l,l.exports,t,e,r,n)}return r[s].exports}for(var o="function"==typeof require&&require,s=0;s ${t}\n`})).join("")}\n`},ul:function(t){if(t.md)return`\n${t.md.replace(new RegExp(n,"ig"),"-")}\n`},ol:function(t){var e=1;if(t.md)return`\n${t.md.replace(new RegExp(n,"ig"),(function(){return e+++"."}))}\n`},li:function(t){if(t.md)return`${n} ${t.md}\n`},hr:function(){return"\n---\n"},code:function(t){if(t.md)return t.isInPreNode?t.md:`\`${t.md}\``},br:function(){return"\n"},pre:function(t){var e=t.md;if(e)return`\n${e=e.split("\n").map((function(t){return` ${t}\n`})).join("")}\n`},p:function(t){var e=t.md;if(e)return`\n${e}\n`},div:function(t){var e=t.md;if(e)return`\n${e}\n`},default:function(t){return t.md},cleanup:function(t){return t.replace(/(^\n+|\n+$)/g,"").replace(/\n{3,}/g,"\n\n")}}},{}],3:[function(t,e,r){var n=t("./commonmark"),i=Object.create(n);i.pre=function(t){return`\n\`\`\`\n${t.md}\n\`\`\`\n`};var o=!1,s=!1,a=0,c=0;function u(){isTr=!1,s=!1,c=0,a=0,o=!1}function l(){for(var t="|",e=c;e>0;e--)t+="--------|";return t}i.table=function(t){var e="";return o||(e=l()+"\n"),s?(u(),`\n${t.md}\n${e}`):(u(),"")},i.tr=function(t){var e;if(a++,e=`\n|${t.md}`,o||2!=a)return`${e}`;var r=l();return o=!0,`\n${r}${e}`},i.th=function(t){return s=!0,c++,`${t.md}|`},i.td=function(t){return s=!0,0==a&&c++,`${t.md.replace(/(
    )|()|(\n)|(\r\n)/g,"")}|`},e.exports=i},{"./commonmark":2}],4:[function(t,e,r){e.exports={CommonMark:t("./commonmark"),MarkdownExtra:t("./markdown-extra"),Gfm:t("./gfm")}},{"./commonmark":2,"./gfm":3,"./markdown-extra":5}],5:[function(t,e,r){var n=t("./commonmark"),i=["id","class","href","src","alt"];function o(t){var e=[],r=t.attrs.id;return r&&e.push(`#${r}`),(r=t.attrs.class)&&e.push(r.split(/\s+/).map((function(t){return`.${t}`})).join(" ")),Object.keys(t.attrs).forEach((function(t){-1==i.indexOf(t)&&e.push(`${t}=${r}`)})),(e=e.join(" ")).length<=0?"":` (${e})`}for(var s=Object.create(n),a=0;a<6;a++)!function(t){s[`h${t}`]=function(e){var r="#".repeat(t);return`\n${r} ${e.md} ${r}${o(e)}\n`}}(a+1);s.a=function(t){return`${n.a(t)}${o(t)}`},s.img=function(t){return`${n.img(t)}${o(t)}`},s.pre=function(t){return`\n\`\`\`\n${t.md}\n\`\`\`\n`};var c=[];s.abbr=function(t){return""!=t.attrs.title&&c.push({word:t.md,title:t.attrs.title}),t.md};var u=!1,l=!1,p=0,h=0;function f(){isTr=!1,l=!1,h=0,p=0,u=!1}function d(){for(var t="|",e=h;e>0;e--)t+="--------|";return t}s.table=function(t){var e="";return u||(e=d()+"\n"),l?(f(),`\n${t.md}\n${e}`):(f(),"")},s.tr=function(t){var e;if(p++,e=`\n|${t.md}`,u||2!=p)return`${e}`;var r=d();return u=!0,`\n${r}${e}`},s.th=function(t){return l=!0,h++,`${t.md}|`},s.td=function(t){return l=!0,0==p&&h++,`${t.md.replace(/(
    )|()|(\n)|(\r\n)/g,"")}|`},s.dl=function(t){var e=t.md;if(e)return`\n${e}\n`},s.dt=function(t){var e=t.md;if(e)return`${e}\n`},s.dd=function(t){var e=t.md;if(e)return`: ${e}\n\n`},s.cleanup=function(t){return n.cleanup(`${t}\n\n${e=c.map((function(t){return`*[${t.word}]: ${t.title}`})).join("\n"),c=[],e}`);var e},e.exports=s},{"./commonmark":2}],6:[function(t,e,r){var n,i,o,s,a=t("htmlparser2"),c=t("./converters/"),u={"&":"&","<":"<",">":">",""":'"',"'":"'","`":"`"," ":" "," ":" "},l=(n=`(?:${Object.keys(u).join("|")})`,i=RegExp(n),o=RegExp(n,"g"),s=function(t){return u[t]},function(t){return t=t||"",i.test(t)?t.replace(o,s):t});e.exports=function(t,e){e=Object.assign({converter:"CommonMark"},e);var r=Object.assign(Object.create(c[e.converter]),e.overides||{}),n=[],i=[],o=!1;var s=new a.Parser({onopentag:function(t,e){var r={name:t,attrs:e,isInPreNode:o};"pre"===t&&(o=!0),n.push(r)},ontext:function(t){if(!/^\s+$/.test(t)){t=l(t);var e=n[n.length-1];e?(e.md=e.md||[],e.md.push(t)):i.push(t)}},onclosetag:function(t){var e,s=n.pop(),a=((e=s).md=e.md&&e.md.join("")||"",(r[e.name]||r.default)(e)||"");if("pre"===t&&(o=!1),0===n.length)return i.push(a);var c=n[n.length-1];c.md=c.md||[],c.md.push(a)}},{decodeEntities:!1});return s.write(t),s.end(),"function"==typeof r.cleanup?r.cleanup(i.join("")):i.join("")}},{"./converters/":4,htmlparser2:47}],7:[function(t,e,r){r.byteLength=function(t){var e=u(t),r=e[0],n=e[1];return 3*(r+n)/4-n},r.toByteArray=function(t){var e,r,n=u(t),s=n[0],a=n[1],c=new o(function(t,e,r){return 3*(e+r)/4-r}(0,s,a)),l=0,p=a>0?s-4:s;for(r=0;r>16&255,c[l++]=e>>8&255,c[l++]=255&e;2===a&&(e=i[t.charCodeAt(r)]<<2|i[t.charCodeAt(r+1)]>>4,c[l++]=255&e);1===a&&(e=i[t.charCodeAt(r)]<<10|i[t.charCodeAt(r+1)]<<4|i[t.charCodeAt(r+2)]>>2,c[l++]=e>>8&255,c[l++]=255&e);return c},r.fromByteArray=function(t){for(var e,r=t.length,i=r%3,o=[],s=16383,a=0,c=r-i;ac?c:a+s));1===i?(e=t[r-1],o.push(n[e>>2]+n[e<<4&63]+"==")):2===i&&(e=(t[r-2]<<8)+t[r-1],o.push(n[e>>10]+n[e>>4&63]+n[e<<2&63]+"="));return o.join("")};for(var n=[],i=[],o="undefined"!=typeof Uint8Array?Uint8Array:Array,s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",a=0,c=s.length;a0)throw new Error("Invalid string. Length must be a multiple of 4");var r=t.indexOf("=");return-1===r&&(r=e),[r,r===e?0:4-r%4]}function l(t,e,r){for(var i,o,s=[],a=e;a>18&63]+n[o>>12&63]+n[o>>6&63]+n[63&o]);return s.join("")}i["-".charCodeAt(0)]=62,i["_".charCodeAt(0)]=63},{}],8:[function(t,e,r){},{}],9:[function(t,e,r){var n=t("buffer"),i=n.Buffer;function o(t,e){for(var r in t)e[r]=t[r]}function s(t,e,r){return i(t,e,r)}i.from&&i.alloc&&i.allocUnsafe&&i.allocUnsafeSlow?e.exports=n:(o(n,r),r.Buffer=s),o(i,s),s.from=function(t,e,r){if("number"==typeof t)throw new TypeError("Argument must not be a number");return i(t,e,r)},s.alloc=function(t,e,r){if("number"!=typeof t)throw new TypeError("Argument must be a number");var n=i(t);return void 0!==e?"string"==typeof r?n.fill(e,r):n.fill(e):n.fill(0),n},s.allocUnsafe=function(t){if("number"!=typeof t)throw new TypeError("Argument must be a number");return i(t)},s.allocUnsafeSlow=function(t){if("number"!=typeof t)throw new TypeError("Argument must be a number");return n.SlowBuffer(t)}},{buffer:11}],10:[function(t,e,r){var n=t("safe-buffer").Buffer,i=n.isEncoding||function(t){switch((t=""+t)&&t.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};function o(t){var e;switch(this.encoding=function(t){var e=function(t){if(!t)return"utf8";for(var e;;)switch(t){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return t;default:if(e)return;t=(""+t).toLowerCase(),e=!0}}(t);if("string"!=typeof e&&(n.isEncoding===i||!i(t)))throw new Error("Unknown encoding: "+t);return e||t}(t),this.encoding){case"utf16le":this.text=c,this.end=u,e=4;break;case"utf8":this.fillLast=a,e=4;break;case"base64":this.text=l,this.end=p,e=3;break;default:return this.write=h,void(this.end=f)}this.lastNeed=0,this.lastTotal=0,this.lastChar=n.allocUnsafe(e)}function s(t){return t<=127?0:t>>5==6?2:t>>4==14?3:t>>3==30?4:t>>6==2?-1:-2}function a(t){var e=this.lastTotal-this.lastNeed,r=function(t,e,r){if(128!=(192&e[0]))return t.lastNeed=0,"�";if(t.lastNeed>1&&e.length>1){if(128!=(192&e[1]))return t.lastNeed=1,"�";if(t.lastNeed>2&&e.length>2&&128!=(192&e[2]))return t.lastNeed=2,"�"}}(this,t);return void 0!==r?r:this.lastNeed<=t.length?(t.copy(this.lastChar,e,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):(t.copy(this.lastChar,e,0,t.length),void(this.lastNeed-=t.length))}function c(t,e){if((t.length-e)%2==0){var r=t.toString("utf16le",e);if(r){var n=r.charCodeAt(r.length-1);if(n>=55296&&n<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=t[t.length-2],this.lastChar[1]=t[t.length-1],r.slice(0,-1)}return r}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=t[t.length-1],t.toString("utf16le",e,t.length-1)}function u(t){var e=t&&t.length?this.write(t):"";if(this.lastNeed){var r=this.lastTotal-this.lastNeed;return e+this.lastChar.toString("utf16le",0,r)}return e}function l(t,e){var r=(t.length-e)%3;return 0===r?t.toString("base64",e):(this.lastNeed=3-r,this.lastTotal=3,1===r?this.lastChar[0]=t[t.length-1]:(this.lastChar[0]=t[t.length-2],this.lastChar[1]=t[t.length-1]),t.toString("base64",e,t.length-r))}function p(t){var e=t&&t.length?this.write(t):"";return this.lastNeed?e+this.lastChar.toString("base64",0,3-this.lastNeed):e}function h(t){return t.toString(this.encoding)}function f(t){return t&&t.length?this.write(t):""}r.StringDecoder=o,o.prototype.write=function(t){if(0===t.length)return"";var e,r;if(this.lastNeed){if(void 0===(e=this.fillLast(t)))return"";r=this.lastNeed,this.lastNeed=0}else r=0;return r=0)return i>0&&(t.lastNeed=i-1),i;if(--n=0)return i>0&&(t.lastNeed=i-2),i;if(--n=0)return i>0&&(2===i?i=0:t.lastNeed=i-3),i;return 0}(this,t,e);if(!this.lastNeed)return t.toString("utf8",e);this.lastTotal=r;var n=t.length-(r-this.lastNeed);return t.copy(this.lastChar,0,n),t.toString("utf8",e,n)},o.prototype.fillLast=function(t){if(this.lastNeed<=t.length)return t.copy(this.lastChar,this.lastTotal-this.lastNeed,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);t.copy(this.lastChar,this.lastTotal-this.lastNeed,0,t.length),this.lastNeed-=t.length}},{"safe-buffer":9}],11:[function(t,e,r){(function(e){(function(){var e=t("base64-js"),n=t("ieee754");r.Buffer=s,r.SlowBuffer=function(t){+t!=t&&(t=0);return s.alloc(+t)},r.INSPECT_MAX_BYTES=50;var i=2147483647;function o(t){if(t>i)throw new RangeError('The value "'+t+'" is invalid for option "size"');var e=new Uint8Array(t);return e.__proto__=s.prototype,e}function s(t,e,r){if("number"==typeof t){if("string"==typeof e)throw new TypeError('The "string" argument must be of type string. Received type number');return u(t)}return a(t,e,r)}function a(t,e,r){if("string"==typeof t)return function(t,e){"string"==typeof e&&""!==e||(e="utf8");if(!s.isEncoding(e))throw new TypeError("Unknown encoding: "+e);var r=0|h(t,e),n=o(r),i=n.write(t,e);i!==r&&(n=n.slice(0,i));return n}(t,e);if(ArrayBuffer.isView(t))return l(t);if(null==t)throw TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof t);if(P(t,ArrayBuffer)||t&&P(t.buffer,ArrayBuffer))return function(t,e,r){if(e<0||t.byteLength=i)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+i.toString(16)+" bytes");return 0|t}function h(t,e){if(s.isBuffer(t))return t.length;if(ArrayBuffer.isView(t)||P(t,ArrayBuffer))return t.byteLength;if("string"!=typeof t)throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof t);var r=t.length,n=arguments.length>2&&!0===arguments[2];if(!n&&0===r)return 0;for(var i=!1;;)switch(e){case"ascii":case"latin1":case"binary":return r;case"utf8":case"utf-8":return I(t).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*r;case"hex":return r>>>1;case"base64":return M(t).length;default:if(i)return n?-1:I(t).length;e=(""+e).toLowerCase(),i=!0}}function f(t,e,r){var n=!1;if((void 0===e||e<0)&&(e=0),e>this.length)return"";if((void 0===r||r>this.length)&&(r=this.length),r<=0)return"";if((r>>>=0)<=(e>>>=0))return"";for(t||(t="utf8");;)switch(t){case"hex":return L(this,e,r);case"utf8":case"utf-8":return E(this,e,r);case"ascii":return T(this,e,r);case"latin1":case"binary":return A(this,e,r);case"base64":return q(this,e,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return k(this,e,r);default:if(n)throw new TypeError("Unknown encoding: "+t);t=(t+"").toLowerCase(),n=!0}}function d(t,e,r){var n=t[e];t[e]=t[r],t[r]=n}function g(t,e,r,n,i){if(0===t.length)return-1;if("string"==typeof r?(n=r,r=0):r>2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),H(r=+r)&&(r=i?0:t.length-1),r<0&&(r=t.length+r),r>=t.length){if(i)return-1;r=t.length-1}else if(r<0){if(!i)return-1;r=0}if("string"==typeof e&&(e=s.from(e,n)),s.isBuffer(e))return 0===e.length?-1:m(t,e,r,n,i);if("number"==typeof e)return e&=255,"function"==typeof Uint8Array.prototype.indexOf?i?Uint8Array.prototype.indexOf.call(t,e,r):Uint8Array.prototype.lastIndexOf.call(t,e,r):m(t,[e],r,n,i);throw new TypeError("val must be string, number or Buffer")}function m(t,e,r,n,i){var o,s=1,a=t.length,c=e.length;if(void 0!==n&&("ucs2"===(n=String(n).toLowerCase())||"ucs-2"===n||"utf16le"===n||"utf-16le"===n)){if(t.length<2||e.length<2)return-1;s=2,a/=2,c/=2,r/=2}function u(t,e){return 1===s?t[e]:t.readUInt16BE(e*s)}if(i){var l=-1;for(o=r;oa&&(r=a-c),o=r;o>=0;o--){for(var p=!0,h=0;hi&&(n=i):n=i;var o=e.length;n>o/2&&(n=o/2);for(var s=0;s>8,i=r%256,o.push(i),o.push(n);return o}(e,t.length-r),t,r,n)}function q(t,r,n){return 0===r&&n===t.length?e.fromByteArray(t):e.fromByteArray(t.slice(r,n))}function E(t,e,r){r=Math.min(t.length,r);for(var n=[],i=e;i239?4:u>223?3:u>191?2:1;if(i+p<=r)switch(p){case 1:u<128&&(l=u);break;case 2:128==(192&(o=t[i+1]))&&(c=(31&u)<<6|63&o)>127&&(l=c);break;case 3:o=t[i+1],s=t[i+2],128==(192&o)&&128==(192&s)&&(c=(15&u)<<12|(63&o)<<6|63&s)>2047&&(c<55296||c>57343)&&(l=c);break;case 4:o=t[i+1],s=t[i+2],a=t[i+3],128==(192&o)&&128==(192&s)&&128==(192&a)&&(c=(15&u)<<18|(63&o)<<12|(63&s)<<6|63&a)>65535&&c<1114112&&(l=c)}null===l?(l=65533,p=1):l>65535&&(l-=65536,n.push(l>>>10&1023|55296),l=56320|1023&l),n.push(l),i+=p}return function(t){var e=t.length;if(e<=S)return String.fromCharCode.apply(String,t);var r="",n=0;for(;ne&&(t+=" ... "),""},s.prototype.compare=function(t,e,r,n,i){if(P(t,Uint8Array)&&(t=s.from(t,t.offset,t.byteLength)),!s.isBuffer(t))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof t);if(void 0===e&&(e=0),void 0===r&&(r=t?t.length:0),void 0===n&&(n=0),void 0===i&&(i=this.length),e<0||r>t.length||n<0||i>this.length)throw new RangeError("out of range index");if(n>=i&&e>=r)return 0;if(n>=i)return-1;if(e>=r)return 1;if(this===t)return 0;for(var o=(i>>>=0)-(n>>>=0),a=(r>>>=0)-(e>>>=0),c=Math.min(o,a),u=this.slice(n,i),l=t.slice(e,r),p=0;p>>=0,isFinite(r)?(r>>>=0,void 0===n&&(n="utf8")):(n=r,r=void 0)}var i=this.length-e;if((void 0===r||r>i)&&(r=i),t.length>0&&(r<0||e<0)||e>this.length)throw new RangeError("Attempt to write outside buffer bounds");n||(n="utf8");for(var o=!1;;)switch(n){case"hex":return b(this,t,e,r);case"utf8":case"utf-8":return y(this,t,e,r);case"ascii":return _(this,t,e,r);case"latin1":case"binary":return v(this,t,e,r);case"base64":return w(this,t,e,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return x(this,t,e,r);default:if(o)throw new TypeError("Unknown encoding: "+n);n=(""+n).toLowerCase(),o=!0}},s.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var S=4096;function T(t,e,r){var n="";r=Math.min(t.length,r);for(var i=e;in)&&(r=n);for(var i="",o=e;or)throw new RangeError("Trying to access beyond buffer length")}function C(t,e,r,n,i,o){if(!s.isBuffer(t))throw new TypeError('"buffer" argument must be a Buffer instance');if(e>i||et.length)throw new RangeError("Index out of range")}function N(t,e,r,n,i,o){if(r+n>t.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("Index out of range")}function B(t,e,r,i,o){return e=+e,r>>>=0,o||N(t,0,r,4),n.write(t,e,r,i,23,4),r+4}function R(t,e,r,i,o){return e=+e,r>>>=0,o||N(t,0,r,8),n.write(t,e,r,i,52,8),r+8}s.prototype.slice=function(t,e){var r=this.length;(t=~~t)<0?(t+=r)<0&&(t=0):t>r&&(t=r),(e=void 0===e?r:~~e)<0?(e+=r)<0&&(e=0):e>r&&(e=r),e>>=0,e>>>=0,r||D(t,e,this.length);for(var n=this[t],i=1,o=0;++o>>=0,e>>>=0,r||D(t,e,this.length);for(var n=this[t+--e],i=1;e>0&&(i*=256);)n+=this[t+--e]*i;return n},s.prototype.readUInt8=function(t,e){return t>>>=0,e||D(t,1,this.length),this[t]},s.prototype.readUInt16LE=function(t,e){return t>>>=0,e||D(t,2,this.length),this[t]|this[t+1]<<8},s.prototype.readUInt16BE=function(t,e){return t>>>=0,e||D(t,2,this.length),this[t]<<8|this[t+1]},s.prototype.readUInt32LE=function(t,e){return t>>>=0,e||D(t,4,this.length),(this[t]|this[t+1]<<8|this[t+2]<<16)+16777216*this[t+3]},s.prototype.readUInt32BE=function(t,e){return t>>>=0,e||D(t,4,this.length),16777216*this[t]+(this[t+1]<<16|this[t+2]<<8|this[t+3])},s.prototype.readIntLE=function(t,e,r){t>>>=0,e>>>=0,r||D(t,e,this.length);for(var n=this[t],i=1,o=0;++o=(i*=128)&&(n-=Math.pow(2,8*e)),n},s.prototype.readIntBE=function(t,e,r){t>>>=0,e>>>=0,r||D(t,e,this.length);for(var n=e,i=1,o=this[t+--n];n>0&&(i*=256);)o+=this[t+--n]*i;return o>=(i*=128)&&(o-=Math.pow(2,8*e)),o},s.prototype.readInt8=function(t,e){return t>>>=0,e||D(t,1,this.length),128&this[t]?-1*(255-this[t]+1):this[t]},s.prototype.readInt16LE=function(t,e){t>>>=0,e||D(t,2,this.length);var r=this[t]|this[t+1]<<8;return 32768&r?4294901760|r:r},s.prototype.readInt16BE=function(t,e){t>>>=0,e||D(t,2,this.length);var r=this[t+1]|this[t]<<8;return 32768&r?4294901760|r:r},s.prototype.readInt32LE=function(t,e){return t>>>=0,e||D(t,4,this.length),this[t]|this[t+1]<<8|this[t+2]<<16|this[t+3]<<24},s.prototype.readInt32BE=function(t,e){return t>>>=0,e||D(t,4,this.length),this[t]<<24|this[t+1]<<16|this[t+2]<<8|this[t+3]},s.prototype.readFloatLE=function(t,e){return t>>>=0,e||D(t,4,this.length),n.read(this,t,!0,23,4)},s.prototype.readFloatBE=function(t,e){return t>>>=0,e||D(t,4,this.length),n.read(this,t,!1,23,4)},s.prototype.readDoubleLE=function(t,e){return t>>>=0,e||D(t,8,this.length),n.read(this,t,!0,52,8)},s.prototype.readDoubleBE=function(t,e){return t>>>=0,e||D(t,8,this.length),n.read(this,t,!1,52,8)},s.prototype.writeUIntLE=function(t,e,r,n){(t=+t,e>>>=0,r>>>=0,n)||C(this,t,e,r,Math.pow(2,8*r)-1,0);var i=1,o=0;for(this[e]=255&t;++o>>=0,r>>>=0,n)||C(this,t,e,r,Math.pow(2,8*r)-1,0);var i=r-1,o=1;for(this[e+i]=255&t;--i>=0&&(o*=256);)this[e+i]=t/o&255;return e+r},s.prototype.writeUInt8=function(t,e,r){return t=+t,e>>>=0,r||C(this,t,e,1,255,0),this[e]=255&t,e+1},s.prototype.writeUInt16LE=function(t,e,r){return t=+t,e>>>=0,r||C(this,t,e,2,65535,0),this[e]=255&t,this[e+1]=t>>>8,e+2},s.prototype.writeUInt16BE=function(t,e,r){return t=+t,e>>>=0,r||C(this,t,e,2,65535,0),this[e]=t>>>8,this[e+1]=255&t,e+2},s.prototype.writeUInt32LE=function(t,e,r){return t=+t,e>>>=0,r||C(this,t,e,4,4294967295,0),this[e+3]=t>>>24,this[e+2]=t>>>16,this[e+1]=t>>>8,this[e]=255&t,e+4},s.prototype.writeUInt32BE=function(t,e,r){return t=+t,e>>>=0,r||C(this,t,e,4,4294967295,0),this[e]=t>>>24,this[e+1]=t>>>16,this[e+2]=t>>>8,this[e+3]=255&t,e+4},s.prototype.writeIntLE=function(t,e,r,n){if(t=+t,e>>>=0,!n){var i=Math.pow(2,8*r-1);C(this,t,e,r,i-1,-i)}var o=0,s=1,a=0;for(this[e]=255&t;++o>0)-a&255;return e+r},s.prototype.writeIntBE=function(t,e,r,n){if(t=+t,e>>>=0,!n){var i=Math.pow(2,8*r-1);C(this,t,e,r,i-1,-i)}var o=r-1,s=1,a=0;for(this[e+o]=255&t;--o>=0&&(s*=256);)t<0&&0===a&&0!==this[e+o+1]&&(a=1),this[e+o]=(t/s>>0)-a&255;return e+r},s.prototype.writeInt8=function(t,e,r){return t=+t,e>>>=0,r||C(this,t,e,1,127,-128),t<0&&(t=255+t+1),this[e]=255&t,e+1},s.prototype.writeInt16LE=function(t,e,r){return t=+t,e>>>=0,r||C(this,t,e,2,32767,-32768),this[e]=255&t,this[e+1]=t>>>8,e+2},s.prototype.writeInt16BE=function(t,e,r){return t=+t,e>>>=0,r||C(this,t,e,2,32767,-32768),this[e]=t>>>8,this[e+1]=255&t,e+2},s.prototype.writeInt32LE=function(t,e,r){return t=+t,e>>>=0,r||C(this,t,e,4,2147483647,-2147483648),this[e]=255&t,this[e+1]=t>>>8,this[e+2]=t>>>16,this[e+3]=t>>>24,e+4},s.prototype.writeInt32BE=function(t,e,r){return t=+t,e>>>=0,r||C(this,t,e,4,2147483647,-2147483648),t<0&&(t=4294967295+t+1),this[e]=t>>>24,this[e+1]=t>>>16,this[e+2]=t>>>8,this[e+3]=255&t,e+4},s.prototype.writeFloatLE=function(t,e,r){return B(this,t,e,!0,r)},s.prototype.writeFloatBE=function(t,e,r){return B(this,t,e,!1,r)},s.prototype.writeDoubleLE=function(t,e,r){return R(this,t,e,!0,r)},s.prototype.writeDoubleBE=function(t,e,r){return R(this,t,e,!1,r)},s.prototype.copy=function(t,e,r,n){if(!s.isBuffer(t))throw new TypeError("argument should be a Buffer");if(r||(r=0),n||0===n||(n=this.length),e>=t.length&&(e=t.length),e||(e=0),n>0&&n=this.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("sourceEnd out of bounds");n>this.length&&(n=this.length),t.length-e=0;--o)t[o+e]=this[o+r];else Uint8Array.prototype.set.call(t,this.subarray(r,n),e);return i},s.prototype.fill=function(t,e,r,n){if("string"==typeof t){if("string"==typeof e?(n=e,e=0,r=this.length):"string"==typeof r&&(n=r,r=this.length),void 0!==n&&"string"!=typeof n)throw new TypeError("encoding must be a string");if("string"==typeof n&&!s.isEncoding(n))throw new TypeError("Unknown encoding: "+n);if(1===t.length){var i=t.charCodeAt(0);("utf8"===n&&i<128||"latin1"===n)&&(t=i)}}else"number"==typeof t&&(t&=255);if(e<0||this.length>>=0,r=void 0===r?this.length:r>>>0,t||(t=0),"number"==typeof t)for(o=e;o55295&&r<57344){if(!i){if(r>56319){(e-=3)>-1&&o.push(239,191,189);continue}if(s+1===n){(e-=3)>-1&&o.push(239,191,189);continue}i=r;continue}if(r<56320){(e-=3)>-1&&o.push(239,191,189),i=r;continue}r=65536+(i-55296<<10|r-56320)}else i&&(e-=3)>-1&&o.push(239,191,189);if(i=null,r<128){if((e-=1)<0)break;o.push(r)}else if(r<2048){if((e-=2)<0)break;o.push(r>>6|192,63&r|128)}else if(r<65536){if((e-=3)<0)break;o.push(r>>12|224,r>>6&63|128,63&r|128)}else{if(!(r<1114112))throw new Error("Invalid code point");if((e-=4)<0)break;o.push(r>>18|240,r>>12&63|128,r>>6&63|128,63&r|128)}}return o}function M(t){return e.toByteArray(function(t){if((t=(t=t.split("=")[0]).trim().replace(U,"")).length<2)return"";for(;t.length%4!=0;)t+="=";return t}(t))}function j(t,e,r,n){for(var i=0;i=e.length||i>=t.length);++i)e[i+r]=t[i];return i}function P(t,e){return t instanceof e||null!=t&&null!=t.constructor&&null!=t.constructor.name&&t.constructor.name===e.name}function H(t){return t!=t}}).call(this)}).call(this,t("buffer").Buffer)},{"base64-js":7,buffer:11,ieee754:48}],12:[function(t,e,r){e.exports={elementNames:{altglyph:"altGlyph",altglyphdef:"altGlyphDef",altglyphitem:"altGlyphItem",animatecolor:"animateColor",animatemotion:"animateMotion",animatetransform:"animateTransform",clippath:"clipPath",feblend:"feBlend",fecolormatrix:"feColorMatrix",fecomponenttransfer:"feComponentTransfer",fecomposite:"feComposite",feconvolvematrix:"feConvolveMatrix",fediffuselighting:"feDiffuseLighting",fedisplacementmap:"feDisplacementMap",fedistantlight:"feDistantLight",fedropshadow:"feDropShadow",feflood:"feFlood",fefunca:"feFuncA",fefuncb:"feFuncB",fefuncg:"feFuncG",fefuncr:"feFuncR",fegaussianblur:"feGaussianBlur",feimage:"feImage",femerge:"feMerge",femergenode:"feMergeNode",femorphology:"feMorphology",feoffset:"feOffset",fepointlight:"fePointLight",fespecularlighting:"feSpecularLighting",fespotlight:"feSpotLight",fetile:"feTile",feturbulence:"feTurbulence",foreignobject:"foreignObject",glyphref:"glyphRef",lineargradient:"linearGradient",radialgradient:"radialGradient",textpath:"textPath"},attributeNames:{definitionurl:"definitionURL",attributename:"attributeName",attributetype:"attributeType",basefrequency:"baseFrequency",baseprofile:"baseProfile",calcmode:"calcMode",clippathunits:"clipPathUnits",diffuseconstant:"diffuseConstant",edgemode:"edgeMode",filterunits:"filterUnits",glyphref:"glyphRef",gradienttransform:"gradientTransform",gradientunits:"gradientUnits",kernelmatrix:"kernelMatrix",kernelunitlength:"kernelUnitLength",keypoints:"keyPoints",keysplines:"keySplines",keytimes:"keyTimes",lengthadjust:"lengthAdjust",limitingconeangle:"limitingConeAngle",markerheight:"markerHeight",markerunits:"markerUnits",markerwidth:"markerWidth",maskcontentunits:"maskContentUnits",maskunits:"maskUnits",numoctaves:"numOctaves",pathlength:"pathLength",patterncontentunits:"patternContentUnits",patterntransform:"patternTransform",patternunits:"patternUnits",pointsatx:"pointsAtX",pointsaty:"pointsAtY",pointsatz:"pointsAtZ",preservealpha:"preserveAlpha",preserveaspectratio:"preserveAspectRatio",primitiveunits:"primitiveUnits",refx:"refX",refy:"refY",repeatcount:"repeatCount",repeatdur:"repeatDur",requiredextensions:"requiredExtensions",requiredfeatures:"requiredFeatures",specularconstant:"specularConstant",specularexponent:"specularExponent",spreadmethod:"spreadMethod",startoffset:"startOffset",stddeviation:"stdDeviation",stitchtiles:"stitchTiles",surfacescale:"surfaceScale",systemlanguage:"systemLanguage",tablevalues:"tableValues",targetx:"targetX",targety:"targetY",textlength:"textLength",viewbox:"viewBox",viewtarget:"viewTarget",xchannelselector:"xChannelSelector",ychannelselector:"yChannelSelector",zoomandpan:"zoomAndPan"}}},{}],13:[function(t,e,r){var n=t("domelementtype"),i=t("entities"),o=t("./foreignNames.json");o.elementNames.__proto__=null,o.attributeNames.__proto__=null;var s={__proto__:null,style:!0,script:!0,xmp:!0,iframe:!0,noembed:!0,noframes:!0,plaintext:!0,noscript:!0};var a={__proto__:null,area:!0,base:!0,basefont:!0,br:!0,col:!0,command:!0,embed:!0,frame:!0,hr:!0,img:!0,input:!0,isindex:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0},c=e.exports=function(t,e){Array.isArray(t)||t.cheerio||(t=[t]),e=e||{};for(var r="",i=0;i=0&&(e=Object.assign({},e,{xmlMode:!1}))),!e.xmlMode&&["svg","math"].indexOf(t.name)>=0&&(e=Object.assign({},e,{xmlMode:"foreign"}));var r="<"+t.name,n=function(t,e){if(t){var r,n="";for(var s in t)r=t[s],n&&(n+=" "),"foreign"===e.xmlMode&&(s=o.attributeNames[s]||s),n+=s,(null!==r&&""!==r||e.xmlMode)&&(n+='="'+(e.decodeEntities?i.encodeXML(r):r.replace(/\"/g,"""))+'"');return n}}(t.attribs,e);return n&&(r+=" "+n),!e.xmlMode||t.children&&0!==t.children.length?(r+=">",t.children&&(r+=c(t.children,e)),a[t.name]&&!e.xmlMode||(r+="")):r+="/>",r}function p(t){return"<"+t.data+">"}function h(t,e){var r=t.data||"";return!e.decodeEntities||t.parent&&t.parent.name in s||(r=i.encodeXML(r)),r}function f(t){return""}function d(t){return"\x3c!--"+t.data+"--\x3e"}},{"./foreignNames.json":12,domelementtype:14,entities:18}],14:[function(t,e,r){var n;Object.defineProperty(r,"__esModule",{value:!0}),r.Doctype=r.CDATA=r.Tag=r.Style=r.Script=r.Comment=r.Directive=r.Text=r.Root=r.isTag=r.ElementType=void 0,function(t){t.Root="root",t.Text="text",t.Directive="directive",t.Comment="comment",t.Script="script",t.Style="style",t.Tag="tag",t.CDATA="cdata",t.Doctype="doctype"}(n=r.ElementType||(r.ElementType={})),r.isTag=function(t){return t.type===n.Tag||t.type===n.Script||t.type===n.Style},r.Root=n.Root,r.Text=n.Text,r.Directive=n.Directive,r.Comment=n.Comment,r.Script=n.Script,r.Style=n.Style,r.Tag=n.Tag,r.CDATA=n.CDATA,r.Doctype=n.Doctype},{}],15:[function(t,e,r){var n=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(r,"__esModule",{value:!0}),r.decodeHTML=r.decodeHTMLStrict=r.decodeXML=void 0;var i=n(t("./maps/entities.json")),o=n(t("./maps/legacy.json")),s=n(t("./maps/xml.json")),a=n(t("./decode_codepoint")),c=/&(?:[a-zA-Z0-9]+|#[xX][\da-fA-F]+|#\d+);/g;function u(t){var e=p(t);return function(t){return String(t).replace(c,e)}}r.decodeXML=u(s.default),r.decodeHTMLStrict=u(i.default);var l=function(t,e){return t65535&&(t-=65536,e+=String.fromCharCode(t>>>10&1023|55296),t=56320|1023&t),e+=String.fromCharCode(t)};r.default=function(t){return t>=55296&&t<=57343||t>1114111?"�":(t in i.default&&(t=i.default[t]),o(t))}},{"./maps/decode.json":19}],17:[function(t,e,r){var n=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(r,"__esModule",{value:!0}),r.escapeUTF8=r.escape=r.encodeNonAsciiHTML=r.encodeHTML=r.encodeXML=void 0;var i=l(n(t("./maps/xml.json")).default),o=p(i);r.encodeXML=m(i);var s,a,c=l(n(t("./maps/entities.json")).default),u=p(c);function l(t){return Object.keys(t).sort().reduce((function(e,r){return e[t[r]]="&"+r+";",e}),{})}function p(t){for(var e=[],r=[],n=0,i=Object.keys(t);n1?f(t):t.charCodeAt(0)).toString(16).toUpperCase()+";"}var g=new RegExp(o.source+"|"+h.source,"g");function m(t){return function(e){return e.replace(g,(function(e){return t[e]||d(e)}))}}r.escape=function(t){return t.replace(g,d)},r.escapeUTF8=function(t){return t.replace(o,d)}},{"./maps/entities.json":20,"./maps/xml.json":22}],18:[function(t,e,r){Object.defineProperty(r,"__esModule",{value:!0}),r.decodeXMLStrict=r.decodeHTML5Strict=r.decodeHTML4Strict=r.decodeHTML5=r.decodeHTML4=r.decodeHTMLStrict=r.decodeHTML=r.decodeXML=r.encodeHTML5=r.encodeHTML4=r.escapeUTF8=r.escape=r.encodeNonAsciiHTML=r.encodeHTML=r.encodeXML=r.encode=r.decodeStrict=r.decode=void 0;var n=t("./decode"),i=t("./encode");r.decode=function(t,e){return(!e||e<=0?n.decodeXML:n.decodeHTML)(t)},r.decodeStrict=function(t,e){return(!e||e<=0?n.decodeXML:n.decodeHTMLStrict)(t)},r.encode=function(t,e){return(!e||e<=0?i.encodeXML:i.encodeHTML)(t)};var o=t("./encode");Object.defineProperty(r,"encodeXML",{enumerable:!0,get:function(){return o.encodeXML}}),Object.defineProperty(r,"encodeHTML",{enumerable:!0,get:function(){return o.encodeHTML}}),Object.defineProperty(r,"encodeNonAsciiHTML",{enumerable:!0,get:function(){return o.encodeNonAsciiHTML}}),Object.defineProperty(r,"escape",{enumerable:!0,get:function(){return o.escape}}),Object.defineProperty(r,"escapeUTF8",{enumerable:!0,get:function(){return o.escapeUTF8}}),Object.defineProperty(r,"encodeHTML4",{enumerable:!0,get:function(){return o.encodeHTML}}),Object.defineProperty(r,"encodeHTML5",{enumerable:!0,get:function(){return o.encodeHTML}});var s=t("./decode");Object.defineProperty(r,"decodeXML",{enumerable:!0,get:function(){return s.decodeXML}}),Object.defineProperty(r,"decodeHTML",{enumerable:!0,get:function(){return s.decodeHTML}}),Object.defineProperty(r,"decodeHTMLStrict",{enumerable:!0,get:function(){return s.decodeHTMLStrict}}),Object.defineProperty(r,"decodeHTML4",{enumerable:!0,get:function(){return s.decodeHTML}}),Object.defineProperty(r,"decodeHTML5",{enumerable:!0,get:function(){return s.decodeHTML}}),Object.defineProperty(r,"decodeHTML4Strict",{enumerable:!0,get:function(){return s.decodeHTMLStrict}}),Object.defineProperty(r,"decodeHTML5Strict",{enumerable:!0,get:function(){return s.decodeHTMLStrict}}),Object.defineProperty(r,"decodeXMLStrict",{enumerable:!0,get:function(){return s.decodeXML}})},{"./decode":15,"./encode":17}],19:[function(t,e,r){e.exports={0:65533,128:8364,130:8218,131:402,132:8222,133:8230,134:8224,135:8225,136:710,137:8240,138:352,139:8249,140:338,142:381,145:8216,146:8217,147:8220,148:8221,149:8226,150:8211,151:8212,152:732,153:8482,154:353,155:8250,156:339,158:382,159:376}},{}],20:[function(t,e,r){e.exports={Aacute:"Á",aacute:"á",Abreve:"Ă",abreve:"ă",ac:"∾",acd:"∿",acE:"∾̳",Acirc:"Â",acirc:"â",acute:"´",Acy:"А",acy:"а",AElig:"Æ",aelig:"æ",af:"⁡",Afr:"𝔄",afr:"𝔞",Agrave:"À",agrave:"à",alefsym:"ℵ",aleph:"ℵ",Alpha:"Α",alpha:"α",Amacr:"Ā",amacr:"ā",amalg:"⨿",amp:"&",AMP:"&",andand:"⩕",And:"⩓",and:"∧",andd:"⩜",andslope:"⩘",andv:"⩚",ang:"∠",ange:"⦤",angle:"∠",angmsdaa:"⦨",angmsdab:"⦩",angmsdac:"⦪",angmsdad:"⦫",angmsdae:"⦬",angmsdaf:"⦭",angmsdag:"⦮",angmsdah:"⦯",angmsd:"∡",angrt:"∟",angrtvb:"⊾",angrtvbd:"⦝",angsph:"∢",angst:"Å",angzarr:"⍼",Aogon:"Ą",aogon:"ą",Aopf:"𝔸",aopf:"𝕒",apacir:"⩯",ap:"≈",apE:"⩰",ape:"≊",apid:"≋",apos:"'",ApplyFunction:"⁡",approx:"≈",approxeq:"≊",Aring:"Å",aring:"å",Ascr:"𝒜",ascr:"𝒶",Assign:"≔",ast:"*",asymp:"≈",asympeq:"≍",Atilde:"Ã",atilde:"ã",Auml:"Ä",auml:"ä",awconint:"∳",awint:"⨑",backcong:"≌",backepsilon:"϶",backprime:"‵",backsim:"∽",backsimeq:"⋍",Backslash:"∖",Barv:"⫧",barvee:"⊽",barwed:"⌅",Barwed:"⌆",barwedge:"⌅",bbrk:"⎵",bbrktbrk:"⎶",bcong:"≌",Bcy:"Б",bcy:"б",bdquo:"„",becaus:"∵",because:"∵",Because:"∵",bemptyv:"⦰",bepsi:"϶",bernou:"ℬ",Bernoullis:"ℬ",Beta:"Β",beta:"β",beth:"ℶ",between:"≬",Bfr:"𝔅",bfr:"𝔟",bigcap:"⋂",bigcirc:"◯",bigcup:"⋃",bigodot:"⨀",bigoplus:"⨁",bigotimes:"⨂",bigsqcup:"⨆",bigstar:"★",bigtriangledown:"▽",bigtriangleup:"△",biguplus:"⨄",bigvee:"⋁",bigwedge:"⋀",bkarow:"⤍",blacklozenge:"⧫",blacksquare:"▪",blacktriangle:"▴",blacktriangledown:"▾",blacktriangleleft:"◂",blacktriangleright:"▸",blank:"␣",blk12:"▒",blk14:"░",blk34:"▓",block:"█",bne:"=⃥",bnequiv:"≡⃥",bNot:"⫭",bnot:"⌐",Bopf:"𝔹",bopf:"𝕓",bot:"⊥",bottom:"⊥",bowtie:"⋈",boxbox:"⧉",boxdl:"┐",boxdL:"╕",boxDl:"╖",boxDL:"╗",boxdr:"┌",boxdR:"╒",boxDr:"╓",boxDR:"╔",boxh:"─",boxH:"═",boxhd:"┬",boxHd:"╤",boxhD:"╥",boxHD:"╦",boxhu:"┴",boxHu:"╧",boxhU:"╨",boxHU:"╩",boxminus:"⊟",boxplus:"⊞",boxtimes:"⊠",boxul:"┘",boxuL:"╛",boxUl:"╜",boxUL:"╝",boxur:"└",boxuR:"╘",boxUr:"╙",boxUR:"╚",boxv:"│",boxV:"║",boxvh:"┼",boxvH:"╪",boxVh:"╫",boxVH:"╬",boxvl:"┤",boxvL:"╡",boxVl:"╢",boxVL:"╣",boxvr:"├",boxvR:"╞",boxVr:"╟",boxVR:"╠",bprime:"‵",breve:"˘",Breve:"˘",brvbar:"¦",bscr:"𝒷",Bscr:"ℬ",bsemi:"⁏",bsim:"∽",bsime:"⋍",bsolb:"⧅",bsol:"\\",bsolhsub:"⟈",bull:"•",bullet:"•",bump:"≎",bumpE:"⪮",bumpe:"≏",Bumpeq:"≎",bumpeq:"≏",Cacute:"Ć",cacute:"ć",capand:"⩄",capbrcup:"⩉",capcap:"⩋",cap:"∩",Cap:"⋒",capcup:"⩇",capdot:"⩀",CapitalDifferentialD:"ⅅ",caps:"∩︀",caret:"⁁",caron:"ˇ",Cayleys:"ℭ",ccaps:"⩍",Ccaron:"Č",ccaron:"č",Ccedil:"Ç",ccedil:"ç",Ccirc:"Ĉ",ccirc:"ĉ",Cconint:"∰",ccups:"⩌",ccupssm:"⩐",Cdot:"Ċ",cdot:"ċ",cedil:"¸",Cedilla:"¸",cemptyv:"⦲",cent:"¢",centerdot:"·",CenterDot:"·",cfr:"𝔠",Cfr:"ℭ",CHcy:"Ч",chcy:"ч",check:"✓",checkmark:"✓",Chi:"Χ",chi:"χ",circ:"ˆ",circeq:"≗",circlearrowleft:"↺",circlearrowright:"↻",circledast:"⊛",circledcirc:"⊚",circleddash:"⊝",CircleDot:"⊙",circledR:"®",circledS:"Ⓢ",CircleMinus:"⊖",CirclePlus:"⊕",CircleTimes:"⊗",cir:"○",cirE:"⧃",cire:"≗",cirfnint:"⨐",cirmid:"⫯",cirscir:"⧂",ClockwiseContourIntegral:"∲",CloseCurlyDoubleQuote:"”",CloseCurlyQuote:"’",clubs:"♣",clubsuit:"♣",colon:":",Colon:"∷",Colone:"⩴",colone:"≔",coloneq:"≔",comma:",",commat:"@",comp:"∁",compfn:"∘",complement:"∁",complexes:"ℂ",cong:"≅",congdot:"⩭",Congruent:"≡",conint:"∮",Conint:"∯",ContourIntegral:"∮",copf:"𝕔",Copf:"ℂ",coprod:"∐",Coproduct:"∐",copy:"©",COPY:"©",copysr:"℗",CounterClockwiseContourIntegral:"∳",crarr:"↵",cross:"✗",Cross:"⨯",Cscr:"𝒞",cscr:"𝒸",csub:"⫏",csube:"⫑",csup:"⫐",csupe:"⫒",ctdot:"⋯",cudarrl:"⤸",cudarrr:"⤵",cuepr:"⋞",cuesc:"⋟",cularr:"↶",cularrp:"⤽",cupbrcap:"⩈",cupcap:"⩆",CupCap:"≍",cup:"∪",Cup:"⋓",cupcup:"⩊",cupdot:"⊍",cupor:"⩅",cups:"∪︀",curarr:"↷",curarrm:"⤼",curlyeqprec:"⋞",curlyeqsucc:"⋟",curlyvee:"⋎",curlywedge:"⋏",curren:"¤",curvearrowleft:"↶",curvearrowright:"↷",cuvee:"⋎",cuwed:"⋏",cwconint:"∲",cwint:"∱",cylcty:"⌭",dagger:"†",Dagger:"‡",daleth:"ℸ",darr:"↓",Darr:"↡",dArr:"⇓",dash:"‐",Dashv:"⫤",dashv:"⊣",dbkarow:"⤏",dblac:"˝",Dcaron:"Ď",dcaron:"ď",Dcy:"Д",dcy:"д",ddagger:"‡",ddarr:"⇊",DD:"ⅅ",dd:"ⅆ",DDotrahd:"⤑",ddotseq:"⩷",deg:"°",Del:"∇",Delta:"Δ",delta:"δ",demptyv:"⦱",dfisht:"⥿",Dfr:"𝔇",dfr:"𝔡",dHar:"⥥",dharl:"⇃",dharr:"⇂",DiacriticalAcute:"´",DiacriticalDot:"˙",DiacriticalDoubleAcute:"˝",DiacriticalGrave:"`",DiacriticalTilde:"˜",diam:"⋄",diamond:"⋄",Diamond:"⋄",diamondsuit:"♦",diams:"♦",die:"¨",DifferentialD:"ⅆ",digamma:"ϝ",disin:"⋲",div:"÷",divide:"÷",divideontimes:"⋇",divonx:"⋇",DJcy:"Ђ",djcy:"ђ",dlcorn:"⌞",dlcrop:"⌍",dollar:"$",Dopf:"𝔻",dopf:"𝕕",Dot:"¨",dot:"˙",DotDot:"⃜",doteq:"≐",doteqdot:"≑",DotEqual:"≐",dotminus:"∸",dotplus:"∔",dotsquare:"⊡",doublebarwedge:"⌆",DoubleContourIntegral:"∯",DoubleDot:"¨",DoubleDownArrow:"⇓",DoubleLeftArrow:"⇐",DoubleLeftRightArrow:"⇔",DoubleLeftTee:"⫤",DoubleLongLeftArrow:"⟸",DoubleLongLeftRightArrow:"⟺",DoubleLongRightArrow:"⟹",DoubleRightArrow:"⇒",DoubleRightTee:"⊨",DoubleUpArrow:"⇑",DoubleUpDownArrow:"⇕",DoubleVerticalBar:"∥",DownArrowBar:"⤓",downarrow:"↓",DownArrow:"↓",Downarrow:"⇓",DownArrowUpArrow:"⇵",DownBreve:"̑",downdownarrows:"⇊",downharpoonleft:"⇃",downharpoonright:"⇂",DownLeftRightVector:"⥐",DownLeftTeeVector:"⥞",DownLeftVectorBar:"⥖",DownLeftVector:"↽",DownRightTeeVector:"⥟",DownRightVectorBar:"⥗",DownRightVector:"⇁",DownTeeArrow:"↧",DownTee:"⊤",drbkarow:"⤐",drcorn:"⌟",drcrop:"⌌",Dscr:"𝒟",dscr:"𝒹",DScy:"Ѕ",dscy:"ѕ",dsol:"⧶",Dstrok:"Đ",dstrok:"đ",dtdot:"⋱",dtri:"▿",dtrif:"▾",duarr:"⇵",duhar:"⥯",dwangle:"⦦",DZcy:"Џ",dzcy:"џ",dzigrarr:"⟿",Eacute:"É",eacute:"é",easter:"⩮",Ecaron:"Ě",ecaron:"ě",Ecirc:"Ê",ecirc:"ê",ecir:"≖",ecolon:"≕",Ecy:"Э",ecy:"э",eDDot:"⩷",Edot:"Ė",edot:"ė",eDot:"≑",ee:"ⅇ",efDot:"≒",Efr:"𝔈",efr:"𝔢",eg:"⪚",Egrave:"È",egrave:"è",egs:"⪖",egsdot:"⪘",el:"⪙",Element:"∈",elinters:"⏧",ell:"ℓ",els:"⪕",elsdot:"⪗",Emacr:"Ē",emacr:"ē",empty:"∅",emptyset:"∅",EmptySmallSquare:"◻",emptyv:"∅",EmptyVerySmallSquare:"▫",emsp13:" ",emsp14:" ",emsp:" ",ENG:"Ŋ",eng:"ŋ",ensp:" ",Eogon:"Ę",eogon:"ę",Eopf:"𝔼",eopf:"𝕖",epar:"⋕",eparsl:"⧣",eplus:"⩱",epsi:"ε",Epsilon:"Ε",epsilon:"ε",epsiv:"ϵ",eqcirc:"≖",eqcolon:"≕",eqsim:"≂",eqslantgtr:"⪖",eqslantless:"⪕",Equal:"⩵",equals:"=",EqualTilde:"≂",equest:"≟",Equilibrium:"⇌",equiv:"≡",equivDD:"⩸",eqvparsl:"⧥",erarr:"⥱",erDot:"≓",escr:"ℯ",Escr:"ℰ",esdot:"≐",Esim:"⩳",esim:"≂",Eta:"Η",eta:"η",ETH:"Ð",eth:"ð",Euml:"Ë",euml:"ë",euro:"€",excl:"!",exist:"∃",Exists:"∃",expectation:"ℰ",exponentiale:"ⅇ",ExponentialE:"ⅇ",fallingdotseq:"≒",Fcy:"Ф",fcy:"ф",female:"♀",ffilig:"ffi",fflig:"ff",ffllig:"ffl",Ffr:"𝔉",ffr:"𝔣",filig:"fi",FilledSmallSquare:"◼",FilledVerySmallSquare:"▪",fjlig:"fj",flat:"♭",fllig:"fl",fltns:"▱",fnof:"ƒ",Fopf:"𝔽",fopf:"𝕗",forall:"∀",ForAll:"∀",fork:"⋔",forkv:"⫙",Fouriertrf:"ℱ",fpartint:"⨍",frac12:"½",frac13:"⅓",frac14:"¼",frac15:"⅕",frac16:"⅙",frac18:"⅛",frac23:"⅔",frac25:"⅖",frac34:"¾",frac35:"⅗",frac38:"⅜",frac45:"⅘",frac56:"⅚",frac58:"⅝",frac78:"⅞",frasl:"⁄",frown:"⌢",fscr:"𝒻",Fscr:"ℱ",gacute:"ǵ",Gamma:"Γ",gamma:"γ",Gammad:"Ϝ",gammad:"ϝ",gap:"⪆",Gbreve:"Ğ",gbreve:"ğ",Gcedil:"Ģ",Gcirc:"Ĝ",gcirc:"ĝ",Gcy:"Г",gcy:"г",Gdot:"Ġ",gdot:"ġ",ge:"≥",gE:"≧",gEl:"⪌",gel:"⋛",geq:"≥",geqq:"≧",geqslant:"⩾",gescc:"⪩",ges:"⩾",gesdot:"⪀",gesdoto:"⪂",gesdotol:"⪄",gesl:"⋛︀",gesles:"⪔",Gfr:"𝔊",gfr:"𝔤",gg:"≫",Gg:"⋙",ggg:"⋙",gimel:"ℷ",GJcy:"Ѓ",gjcy:"ѓ",gla:"⪥",gl:"≷",glE:"⪒",glj:"⪤",gnap:"⪊",gnapprox:"⪊",gne:"⪈",gnE:"≩",gneq:"⪈",gneqq:"≩",gnsim:"⋧",Gopf:"𝔾",gopf:"𝕘",grave:"`",GreaterEqual:"≥",GreaterEqualLess:"⋛",GreaterFullEqual:"≧",GreaterGreater:"⪢",GreaterLess:"≷",GreaterSlantEqual:"⩾",GreaterTilde:"≳",Gscr:"𝒢",gscr:"ℊ",gsim:"≳",gsime:"⪎",gsiml:"⪐",gtcc:"⪧",gtcir:"⩺",gt:">",GT:">",Gt:"≫",gtdot:"⋗",gtlPar:"⦕",gtquest:"⩼",gtrapprox:"⪆",gtrarr:"⥸",gtrdot:"⋗",gtreqless:"⋛",gtreqqless:"⪌",gtrless:"≷",gtrsim:"≳",gvertneqq:"≩︀",gvnE:"≩︀",Hacek:"ˇ",hairsp:" ",half:"½",hamilt:"ℋ",HARDcy:"Ъ",hardcy:"ъ",harrcir:"⥈",harr:"↔",hArr:"⇔",harrw:"↭",Hat:"^",hbar:"ℏ",Hcirc:"Ĥ",hcirc:"ĥ",hearts:"♥",heartsuit:"♥",hellip:"…",hercon:"⊹",hfr:"𝔥",Hfr:"ℌ",HilbertSpace:"ℋ",hksearow:"⤥",hkswarow:"⤦",hoarr:"⇿",homtht:"∻",hookleftarrow:"↩",hookrightarrow:"↪",hopf:"𝕙",Hopf:"ℍ",horbar:"―",HorizontalLine:"─",hscr:"𝒽",Hscr:"ℋ",hslash:"ℏ",Hstrok:"Ħ",hstrok:"ħ",HumpDownHump:"≎",HumpEqual:"≏",hybull:"⁃",hyphen:"‐",Iacute:"Í",iacute:"í",ic:"⁣",Icirc:"Î",icirc:"î",Icy:"И",icy:"и",Idot:"İ",IEcy:"Е",iecy:"е",iexcl:"¡",iff:"⇔",ifr:"𝔦",Ifr:"ℑ",Igrave:"Ì",igrave:"ì",ii:"ⅈ",iiiint:"⨌",iiint:"∭",iinfin:"⧜",iiota:"℩",IJlig:"IJ",ijlig:"ij",Imacr:"Ī",imacr:"ī",image:"ℑ",ImaginaryI:"ⅈ",imagline:"ℐ",imagpart:"ℑ",imath:"ı",Im:"ℑ",imof:"⊷",imped:"Ƶ",Implies:"⇒",incare:"℅",in:"∈",infin:"∞",infintie:"⧝",inodot:"ı",intcal:"⊺",int:"∫",Int:"∬",integers:"ℤ",Integral:"∫",intercal:"⊺",Intersection:"⋂",intlarhk:"⨗",intprod:"⨼",InvisibleComma:"⁣",InvisibleTimes:"⁢",IOcy:"Ё",iocy:"ё",Iogon:"Į",iogon:"į",Iopf:"𝕀",iopf:"𝕚",Iota:"Ι",iota:"ι",iprod:"⨼",iquest:"¿",iscr:"𝒾",Iscr:"ℐ",isin:"∈",isindot:"⋵",isinE:"⋹",isins:"⋴",isinsv:"⋳",isinv:"∈",it:"⁢",Itilde:"Ĩ",itilde:"ĩ",Iukcy:"І",iukcy:"і",Iuml:"Ï",iuml:"ï",Jcirc:"Ĵ",jcirc:"ĵ",Jcy:"Й",jcy:"й",Jfr:"𝔍",jfr:"𝔧",jmath:"ȷ",Jopf:"𝕁",jopf:"𝕛",Jscr:"𝒥",jscr:"𝒿",Jsercy:"Ј",jsercy:"ј",Jukcy:"Є",jukcy:"є",Kappa:"Κ",kappa:"κ",kappav:"ϰ",Kcedil:"Ķ",kcedil:"ķ",Kcy:"К",kcy:"к",Kfr:"𝔎",kfr:"𝔨",kgreen:"ĸ",KHcy:"Х",khcy:"х",KJcy:"Ќ",kjcy:"ќ",Kopf:"𝕂",kopf:"𝕜",Kscr:"𝒦",kscr:"𝓀",lAarr:"⇚",Lacute:"Ĺ",lacute:"ĺ",laemptyv:"⦴",lagran:"ℒ",Lambda:"Λ",lambda:"λ",lang:"⟨",Lang:"⟪",langd:"⦑",langle:"⟨",lap:"⪅",Laplacetrf:"ℒ",laquo:"«",larrb:"⇤",larrbfs:"⤟",larr:"←",Larr:"↞",lArr:"⇐",larrfs:"⤝",larrhk:"↩",larrlp:"↫",larrpl:"⤹",larrsim:"⥳",larrtl:"↢",latail:"⤙",lAtail:"⤛",lat:"⪫",late:"⪭",lates:"⪭︀",lbarr:"⤌",lBarr:"⤎",lbbrk:"❲",lbrace:"{",lbrack:"[",lbrke:"⦋",lbrksld:"⦏",lbrkslu:"⦍",Lcaron:"Ľ",lcaron:"ľ",Lcedil:"Ļ",lcedil:"ļ",lceil:"⌈",lcub:"{",Lcy:"Л",lcy:"л",ldca:"⤶",ldquo:"“",ldquor:"„",ldrdhar:"⥧",ldrushar:"⥋",ldsh:"↲",le:"≤",lE:"≦",LeftAngleBracket:"⟨",LeftArrowBar:"⇤",leftarrow:"←",LeftArrow:"←",Leftarrow:"⇐",LeftArrowRightArrow:"⇆",leftarrowtail:"↢",LeftCeiling:"⌈",LeftDoubleBracket:"⟦",LeftDownTeeVector:"⥡",LeftDownVectorBar:"⥙",LeftDownVector:"⇃",LeftFloor:"⌊",leftharpoondown:"↽",leftharpoonup:"↼",leftleftarrows:"⇇",leftrightarrow:"↔",LeftRightArrow:"↔",Leftrightarrow:"⇔",leftrightarrows:"⇆",leftrightharpoons:"⇋",leftrightsquigarrow:"↭",LeftRightVector:"⥎",LeftTeeArrow:"↤",LeftTee:"⊣",LeftTeeVector:"⥚",leftthreetimes:"⋋",LeftTriangleBar:"⧏",LeftTriangle:"⊲",LeftTriangleEqual:"⊴",LeftUpDownVector:"⥑",LeftUpTeeVector:"⥠",LeftUpVectorBar:"⥘",LeftUpVector:"↿",LeftVectorBar:"⥒",LeftVector:"↼",lEg:"⪋",leg:"⋚",leq:"≤",leqq:"≦",leqslant:"⩽",lescc:"⪨",les:"⩽",lesdot:"⩿",lesdoto:"⪁",lesdotor:"⪃",lesg:"⋚︀",lesges:"⪓",lessapprox:"⪅",lessdot:"⋖",lesseqgtr:"⋚",lesseqqgtr:"⪋",LessEqualGreater:"⋚",LessFullEqual:"≦",LessGreater:"≶",lessgtr:"≶",LessLess:"⪡",lesssim:"≲",LessSlantEqual:"⩽",LessTilde:"≲",lfisht:"⥼",lfloor:"⌊",Lfr:"𝔏",lfr:"𝔩",lg:"≶",lgE:"⪑",lHar:"⥢",lhard:"↽",lharu:"↼",lharul:"⥪",lhblk:"▄",LJcy:"Љ",ljcy:"љ",llarr:"⇇",ll:"≪",Ll:"⋘",llcorner:"⌞",Lleftarrow:"⇚",llhard:"⥫",lltri:"◺",Lmidot:"Ŀ",lmidot:"ŀ",lmoustache:"⎰",lmoust:"⎰",lnap:"⪉",lnapprox:"⪉",lne:"⪇",lnE:"≨",lneq:"⪇",lneqq:"≨",lnsim:"⋦",loang:"⟬",loarr:"⇽",lobrk:"⟦",longleftarrow:"⟵",LongLeftArrow:"⟵",Longleftarrow:"⟸",longleftrightarrow:"⟷",LongLeftRightArrow:"⟷",Longleftrightarrow:"⟺",longmapsto:"⟼",longrightarrow:"⟶",LongRightArrow:"⟶",Longrightarrow:"⟹",looparrowleft:"↫",looparrowright:"↬",lopar:"⦅",Lopf:"𝕃",lopf:"𝕝",loplus:"⨭",lotimes:"⨴",lowast:"∗",lowbar:"_",LowerLeftArrow:"↙",LowerRightArrow:"↘",loz:"◊",lozenge:"◊",lozf:"⧫",lpar:"(",lparlt:"⦓",lrarr:"⇆",lrcorner:"⌟",lrhar:"⇋",lrhard:"⥭",lrm:"‎",lrtri:"⊿",lsaquo:"‹",lscr:"𝓁",Lscr:"ℒ",lsh:"↰",Lsh:"↰",lsim:"≲",lsime:"⪍",lsimg:"⪏",lsqb:"[",lsquo:"‘",lsquor:"‚",Lstrok:"Ł",lstrok:"ł",ltcc:"⪦",ltcir:"⩹",lt:"<",LT:"<",Lt:"≪",ltdot:"⋖",lthree:"⋋",ltimes:"⋉",ltlarr:"⥶",ltquest:"⩻",ltri:"◃",ltrie:"⊴",ltrif:"◂",ltrPar:"⦖",lurdshar:"⥊",luruhar:"⥦",lvertneqq:"≨︀",lvnE:"≨︀",macr:"¯",male:"♂",malt:"✠",maltese:"✠",Map:"⤅",map:"↦",mapsto:"↦",mapstodown:"↧",mapstoleft:"↤",mapstoup:"↥",marker:"▮",mcomma:"⨩",Mcy:"М",mcy:"м",mdash:"—",mDDot:"∺",measuredangle:"∡",MediumSpace:" ",Mellintrf:"ℳ",Mfr:"𝔐",mfr:"𝔪",mho:"℧",micro:"µ",midast:"*",midcir:"⫰",mid:"∣",middot:"·",minusb:"⊟",minus:"−",minusd:"∸",minusdu:"⨪",MinusPlus:"∓",mlcp:"⫛",mldr:"…",mnplus:"∓",models:"⊧",Mopf:"𝕄",mopf:"𝕞",mp:"∓",mscr:"𝓂",Mscr:"ℳ",mstpos:"∾",Mu:"Μ",mu:"μ",multimap:"⊸",mumap:"⊸",nabla:"∇",Nacute:"Ń",nacute:"ń",nang:"∠⃒",nap:"≉",napE:"⩰̸",napid:"≋̸",napos:"ʼn",napprox:"≉",natural:"♮",naturals:"ℕ",natur:"♮",nbsp:" ",nbump:"≎̸",nbumpe:"≏̸",ncap:"⩃",Ncaron:"Ň",ncaron:"ň",Ncedil:"Ņ",ncedil:"ņ",ncong:"≇",ncongdot:"⩭̸",ncup:"⩂",Ncy:"Н",ncy:"н",ndash:"–",nearhk:"⤤",nearr:"↗",neArr:"⇗",nearrow:"↗",ne:"≠",nedot:"≐̸",NegativeMediumSpace:"​",NegativeThickSpace:"​",NegativeThinSpace:"​",NegativeVeryThinSpace:"​",nequiv:"≢",nesear:"⤨",nesim:"≂̸",NestedGreaterGreater:"≫",NestedLessLess:"≪",NewLine:"\n",nexist:"∄",nexists:"∄",Nfr:"𝔑",nfr:"𝔫",ngE:"≧̸",nge:"≱",ngeq:"≱",ngeqq:"≧̸",ngeqslant:"⩾̸",nges:"⩾̸",nGg:"⋙̸",ngsim:"≵",nGt:"≫⃒",ngt:"≯",ngtr:"≯",nGtv:"≫̸",nharr:"↮",nhArr:"⇎",nhpar:"⫲",ni:"∋",nis:"⋼",nisd:"⋺",niv:"∋",NJcy:"Њ",njcy:"њ",nlarr:"↚",nlArr:"⇍",nldr:"‥",nlE:"≦̸",nle:"≰",nleftarrow:"↚",nLeftarrow:"⇍",nleftrightarrow:"↮",nLeftrightarrow:"⇎",nleq:"≰",nleqq:"≦̸",nleqslant:"⩽̸",nles:"⩽̸",nless:"≮",nLl:"⋘̸",nlsim:"≴",nLt:"≪⃒",nlt:"≮",nltri:"⋪",nltrie:"⋬",nLtv:"≪̸",nmid:"∤",NoBreak:"⁠",NonBreakingSpace:" ",nopf:"𝕟",Nopf:"ℕ",Not:"⫬",not:"¬",NotCongruent:"≢",NotCupCap:"≭",NotDoubleVerticalBar:"∦",NotElement:"∉",NotEqual:"≠",NotEqualTilde:"≂̸",NotExists:"∄",NotGreater:"≯",NotGreaterEqual:"≱",NotGreaterFullEqual:"≧̸",NotGreaterGreater:"≫̸",NotGreaterLess:"≹",NotGreaterSlantEqual:"⩾̸",NotGreaterTilde:"≵",NotHumpDownHump:"≎̸",NotHumpEqual:"≏̸",notin:"∉",notindot:"⋵̸",notinE:"⋹̸",notinva:"∉",notinvb:"⋷",notinvc:"⋶",NotLeftTriangleBar:"⧏̸",NotLeftTriangle:"⋪",NotLeftTriangleEqual:"⋬",NotLess:"≮",NotLessEqual:"≰",NotLessGreater:"≸",NotLessLess:"≪̸",NotLessSlantEqual:"⩽̸",NotLessTilde:"≴",NotNestedGreaterGreater:"⪢̸",NotNestedLessLess:"⪡̸",notni:"∌",notniva:"∌",notnivb:"⋾",notnivc:"⋽",NotPrecedes:"⊀",NotPrecedesEqual:"⪯̸",NotPrecedesSlantEqual:"⋠",NotReverseElement:"∌",NotRightTriangleBar:"⧐̸",NotRightTriangle:"⋫",NotRightTriangleEqual:"⋭",NotSquareSubset:"⊏̸",NotSquareSubsetEqual:"⋢",NotSquareSuperset:"⊐̸",NotSquareSupersetEqual:"⋣",NotSubset:"⊂⃒",NotSubsetEqual:"⊈",NotSucceeds:"⊁",NotSucceedsEqual:"⪰̸",NotSucceedsSlantEqual:"⋡",NotSucceedsTilde:"≿̸",NotSuperset:"⊃⃒",NotSupersetEqual:"⊉",NotTilde:"≁",NotTildeEqual:"≄",NotTildeFullEqual:"≇",NotTildeTilde:"≉",NotVerticalBar:"∤",nparallel:"∦",npar:"∦",nparsl:"⫽⃥",npart:"∂̸",npolint:"⨔",npr:"⊀",nprcue:"⋠",nprec:"⊀",npreceq:"⪯̸",npre:"⪯̸",nrarrc:"⤳̸",nrarr:"↛",nrArr:"⇏",nrarrw:"↝̸",nrightarrow:"↛",nRightarrow:"⇏",nrtri:"⋫",nrtrie:"⋭",nsc:"⊁",nsccue:"⋡",nsce:"⪰̸",Nscr:"𝒩",nscr:"𝓃",nshortmid:"∤",nshortparallel:"∦",nsim:"≁",nsime:"≄",nsimeq:"≄",nsmid:"∤",nspar:"∦",nsqsube:"⋢",nsqsupe:"⋣",nsub:"⊄",nsubE:"⫅̸",nsube:"⊈",nsubset:"⊂⃒",nsubseteq:"⊈",nsubseteqq:"⫅̸",nsucc:"⊁",nsucceq:"⪰̸",nsup:"⊅",nsupE:"⫆̸",nsupe:"⊉",nsupset:"⊃⃒",nsupseteq:"⊉",nsupseteqq:"⫆̸",ntgl:"≹",Ntilde:"Ñ",ntilde:"ñ",ntlg:"≸",ntriangleleft:"⋪",ntrianglelefteq:"⋬",ntriangleright:"⋫",ntrianglerighteq:"⋭",Nu:"Ν",nu:"ν",num:"#",numero:"№",numsp:" ",nvap:"≍⃒",nvdash:"⊬",nvDash:"⊭",nVdash:"⊮",nVDash:"⊯",nvge:"≥⃒",nvgt:">⃒",nvHarr:"⤄",nvinfin:"⧞",nvlArr:"⤂",nvle:"≤⃒",nvlt:"<⃒",nvltrie:"⊴⃒",nvrArr:"⤃",nvrtrie:"⊵⃒",nvsim:"∼⃒",nwarhk:"⤣",nwarr:"↖",nwArr:"⇖",nwarrow:"↖",nwnear:"⤧",Oacute:"Ó",oacute:"ó",oast:"⊛",Ocirc:"Ô",ocirc:"ô",ocir:"⊚",Ocy:"О",ocy:"о",odash:"⊝",Odblac:"Ő",odblac:"ő",odiv:"⨸",odot:"⊙",odsold:"⦼",OElig:"Œ",oelig:"œ",ofcir:"⦿",Ofr:"𝔒",ofr:"𝔬",ogon:"˛",Ograve:"Ò",ograve:"ò",ogt:"⧁",ohbar:"⦵",ohm:"Ω",oint:"∮",olarr:"↺",olcir:"⦾",olcross:"⦻",oline:"‾",olt:"⧀",Omacr:"Ō",omacr:"ō",Omega:"Ω",omega:"ω",Omicron:"Ο",omicron:"ο",omid:"⦶",ominus:"⊖",Oopf:"𝕆",oopf:"𝕠",opar:"⦷",OpenCurlyDoubleQuote:"“",OpenCurlyQuote:"‘",operp:"⦹",oplus:"⊕",orarr:"↻",Or:"⩔",or:"∨",ord:"⩝",order:"ℴ",orderof:"ℴ",ordf:"ª",ordm:"º",origof:"⊶",oror:"⩖",orslope:"⩗",orv:"⩛",oS:"Ⓢ",Oscr:"𝒪",oscr:"ℴ",Oslash:"Ø",oslash:"ø",osol:"⊘",Otilde:"Õ",otilde:"õ",otimesas:"⨶",Otimes:"⨷",otimes:"⊗",Ouml:"Ö",ouml:"ö",ovbar:"⌽",OverBar:"‾",OverBrace:"⏞",OverBracket:"⎴",OverParenthesis:"⏜",para:"¶",parallel:"∥",par:"∥",parsim:"⫳",parsl:"⫽",part:"∂",PartialD:"∂",Pcy:"П",pcy:"п",percnt:"%",period:".",permil:"‰",perp:"⊥",pertenk:"‱",Pfr:"𝔓",pfr:"𝔭",Phi:"Φ",phi:"φ",phiv:"ϕ",phmmat:"ℳ",phone:"☎",Pi:"Π",pi:"π",pitchfork:"⋔",piv:"ϖ",planck:"ℏ",planckh:"ℎ",plankv:"ℏ",plusacir:"⨣",plusb:"⊞",pluscir:"⨢",plus:"+",plusdo:"∔",plusdu:"⨥",pluse:"⩲",PlusMinus:"±",plusmn:"±",plussim:"⨦",plustwo:"⨧",pm:"±",Poincareplane:"ℌ",pointint:"⨕",popf:"𝕡",Popf:"ℙ",pound:"£",prap:"⪷",Pr:"⪻",pr:"≺",prcue:"≼",precapprox:"⪷",prec:"≺",preccurlyeq:"≼",Precedes:"≺",PrecedesEqual:"⪯",PrecedesSlantEqual:"≼",PrecedesTilde:"≾",preceq:"⪯",precnapprox:"⪹",precneqq:"⪵",precnsim:"⋨",pre:"⪯",prE:"⪳",precsim:"≾",prime:"′",Prime:"″",primes:"ℙ",prnap:"⪹",prnE:"⪵",prnsim:"⋨",prod:"∏",Product:"∏",profalar:"⌮",profline:"⌒",profsurf:"⌓",prop:"∝",Proportional:"∝",Proportion:"∷",propto:"∝",prsim:"≾",prurel:"⊰",Pscr:"𝒫",pscr:"𝓅",Psi:"Ψ",psi:"ψ",puncsp:" ",Qfr:"𝔔",qfr:"𝔮",qint:"⨌",qopf:"𝕢",Qopf:"ℚ",qprime:"⁗",Qscr:"𝒬",qscr:"𝓆",quaternions:"ℍ",quatint:"⨖",quest:"?",questeq:"≟",quot:'"',QUOT:'"',rAarr:"⇛",race:"∽̱",Racute:"Ŕ",racute:"ŕ",radic:"√",raemptyv:"⦳",rang:"⟩",Rang:"⟫",rangd:"⦒",range:"⦥",rangle:"⟩",raquo:"»",rarrap:"⥵",rarrb:"⇥",rarrbfs:"⤠",rarrc:"⤳",rarr:"→",Rarr:"↠",rArr:"⇒",rarrfs:"⤞",rarrhk:"↪",rarrlp:"↬",rarrpl:"⥅",rarrsim:"⥴",Rarrtl:"⤖",rarrtl:"↣",rarrw:"↝",ratail:"⤚",rAtail:"⤜",ratio:"∶",rationals:"ℚ",rbarr:"⤍",rBarr:"⤏",RBarr:"⤐",rbbrk:"❳",rbrace:"}",rbrack:"]",rbrke:"⦌",rbrksld:"⦎",rbrkslu:"⦐",Rcaron:"Ř",rcaron:"ř",Rcedil:"Ŗ",rcedil:"ŗ",rceil:"⌉",rcub:"}",Rcy:"Р",rcy:"р",rdca:"⤷",rdldhar:"⥩",rdquo:"”",rdquor:"”",rdsh:"↳",real:"ℜ",realine:"ℛ",realpart:"ℜ",reals:"ℝ",Re:"ℜ",rect:"▭",reg:"®",REG:"®",ReverseElement:"∋",ReverseEquilibrium:"⇋",ReverseUpEquilibrium:"⥯",rfisht:"⥽",rfloor:"⌋",rfr:"𝔯",Rfr:"ℜ",rHar:"⥤",rhard:"⇁",rharu:"⇀",rharul:"⥬",Rho:"Ρ",rho:"ρ",rhov:"ϱ",RightAngleBracket:"⟩",RightArrowBar:"⇥",rightarrow:"→",RightArrow:"→",Rightarrow:"⇒",RightArrowLeftArrow:"⇄",rightarrowtail:"↣",RightCeiling:"⌉",RightDoubleBracket:"⟧",RightDownTeeVector:"⥝",RightDownVectorBar:"⥕",RightDownVector:"⇂",RightFloor:"⌋",rightharpoondown:"⇁",rightharpoonup:"⇀",rightleftarrows:"⇄",rightleftharpoons:"⇌",rightrightarrows:"⇉",rightsquigarrow:"↝",RightTeeArrow:"↦",RightTee:"⊢",RightTeeVector:"⥛",rightthreetimes:"⋌",RightTriangleBar:"⧐",RightTriangle:"⊳",RightTriangleEqual:"⊵",RightUpDownVector:"⥏",RightUpTeeVector:"⥜",RightUpVectorBar:"⥔",RightUpVector:"↾",RightVectorBar:"⥓",RightVector:"⇀",ring:"˚",risingdotseq:"≓",rlarr:"⇄",rlhar:"⇌",rlm:"‏",rmoustache:"⎱",rmoust:"⎱",rnmid:"⫮",roang:"⟭",roarr:"⇾",robrk:"⟧",ropar:"⦆",ropf:"𝕣",Ropf:"ℝ",roplus:"⨮",rotimes:"⨵",RoundImplies:"⥰",rpar:")",rpargt:"⦔",rppolint:"⨒",rrarr:"⇉",Rrightarrow:"⇛",rsaquo:"›",rscr:"𝓇",Rscr:"ℛ",rsh:"↱",Rsh:"↱",rsqb:"]",rsquo:"’",rsquor:"’",rthree:"⋌",rtimes:"⋊",rtri:"▹",rtrie:"⊵",rtrif:"▸",rtriltri:"⧎",RuleDelayed:"⧴",ruluhar:"⥨",rx:"℞",Sacute:"Ś",sacute:"ś",sbquo:"‚",scap:"⪸",Scaron:"Š",scaron:"š",Sc:"⪼",sc:"≻",sccue:"≽",sce:"⪰",scE:"⪴",Scedil:"Ş",scedil:"ş",Scirc:"Ŝ",scirc:"ŝ",scnap:"⪺",scnE:"⪶",scnsim:"⋩",scpolint:"⨓",scsim:"≿",Scy:"С",scy:"с",sdotb:"⊡",sdot:"⋅",sdote:"⩦",searhk:"⤥",searr:"↘",seArr:"⇘",searrow:"↘",sect:"§",semi:";",seswar:"⤩",setminus:"∖",setmn:"∖",sext:"✶",Sfr:"𝔖",sfr:"𝔰",sfrown:"⌢",sharp:"♯",SHCHcy:"Щ",shchcy:"щ",SHcy:"Ш",shcy:"ш",ShortDownArrow:"↓",ShortLeftArrow:"←",shortmid:"∣",shortparallel:"∥",ShortRightArrow:"→",ShortUpArrow:"↑",shy:"­",Sigma:"Σ",sigma:"σ",sigmaf:"ς",sigmav:"ς",sim:"∼",simdot:"⩪",sime:"≃",simeq:"≃",simg:"⪞",simgE:"⪠",siml:"⪝",simlE:"⪟",simne:"≆",simplus:"⨤",simrarr:"⥲",slarr:"←",SmallCircle:"∘",smallsetminus:"∖",smashp:"⨳",smeparsl:"⧤",smid:"∣",smile:"⌣",smt:"⪪",smte:"⪬",smtes:"⪬︀",SOFTcy:"Ь",softcy:"ь",solbar:"⌿",solb:"⧄",sol:"/",Sopf:"𝕊",sopf:"𝕤",spades:"♠",spadesuit:"♠",spar:"∥",sqcap:"⊓",sqcaps:"⊓︀",sqcup:"⊔",sqcups:"⊔︀",Sqrt:"√",sqsub:"⊏",sqsube:"⊑",sqsubset:"⊏",sqsubseteq:"⊑",sqsup:"⊐",sqsupe:"⊒",sqsupset:"⊐",sqsupseteq:"⊒",square:"□",Square:"□",SquareIntersection:"⊓",SquareSubset:"⊏",SquareSubsetEqual:"⊑",SquareSuperset:"⊐",SquareSupersetEqual:"⊒",SquareUnion:"⊔",squarf:"▪",squ:"□",squf:"▪",srarr:"→",Sscr:"𝒮",sscr:"𝓈",ssetmn:"∖",ssmile:"⌣",sstarf:"⋆",Star:"⋆",star:"☆",starf:"★",straightepsilon:"ϵ",straightphi:"ϕ",strns:"¯",sub:"⊂",Sub:"⋐",subdot:"⪽",subE:"⫅",sube:"⊆",subedot:"⫃",submult:"⫁",subnE:"⫋",subne:"⊊",subplus:"⪿",subrarr:"⥹",subset:"⊂",Subset:"⋐",subseteq:"⊆",subseteqq:"⫅",SubsetEqual:"⊆",subsetneq:"⊊",subsetneqq:"⫋",subsim:"⫇",subsub:"⫕",subsup:"⫓",succapprox:"⪸",succ:"≻",succcurlyeq:"≽",Succeeds:"≻",SucceedsEqual:"⪰",SucceedsSlantEqual:"≽",SucceedsTilde:"≿",succeq:"⪰",succnapprox:"⪺",succneqq:"⪶",succnsim:"⋩",succsim:"≿",SuchThat:"∋",sum:"∑",Sum:"∑",sung:"♪",sup1:"¹",sup2:"²",sup3:"³",sup:"⊃",Sup:"⋑",supdot:"⪾",supdsub:"⫘",supE:"⫆",supe:"⊇",supedot:"⫄",Superset:"⊃",SupersetEqual:"⊇",suphsol:"⟉",suphsub:"⫗",suplarr:"⥻",supmult:"⫂",supnE:"⫌",supne:"⊋",supplus:"⫀",supset:"⊃",Supset:"⋑",supseteq:"⊇",supseteqq:"⫆",supsetneq:"⊋",supsetneqq:"⫌",supsim:"⫈",supsub:"⫔",supsup:"⫖",swarhk:"⤦",swarr:"↙",swArr:"⇙",swarrow:"↙",swnwar:"⤪",szlig:"ß",Tab:"\t",target:"⌖",Tau:"Τ",tau:"τ",tbrk:"⎴",Tcaron:"Ť",tcaron:"ť",Tcedil:"Ţ",tcedil:"ţ",Tcy:"Т",tcy:"т",tdot:"⃛",telrec:"⌕",Tfr:"𝔗",tfr:"𝔱",there4:"∴",therefore:"∴",Therefore:"∴",Theta:"Θ",theta:"θ",thetasym:"ϑ",thetav:"ϑ",thickapprox:"≈",thicksim:"∼",ThickSpace:"  ",ThinSpace:" ",thinsp:" ",thkap:"≈",thksim:"∼",THORN:"Þ",thorn:"þ",tilde:"˜",Tilde:"∼",TildeEqual:"≃",TildeFullEqual:"≅",TildeTilde:"≈",timesbar:"⨱",timesb:"⊠",times:"×",timesd:"⨰",tint:"∭",toea:"⤨",topbot:"⌶",topcir:"⫱",top:"⊤",Topf:"𝕋",topf:"𝕥",topfork:"⫚",tosa:"⤩",tprime:"‴",trade:"™",TRADE:"™",triangle:"▵",triangledown:"▿",triangleleft:"◃",trianglelefteq:"⊴",triangleq:"≜",triangleright:"▹",trianglerighteq:"⊵",tridot:"◬",trie:"≜",triminus:"⨺",TripleDot:"⃛",triplus:"⨹",trisb:"⧍",tritime:"⨻",trpezium:"⏢",Tscr:"𝒯",tscr:"𝓉",TScy:"Ц",tscy:"ц",TSHcy:"Ћ",tshcy:"ћ",Tstrok:"Ŧ",tstrok:"ŧ",twixt:"≬",twoheadleftarrow:"↞",twoheadrightarrow:"↠",Uacute:"Ú",uacute:"ú",uarr:"↑",Uarr:"↟",uArr:"⇑",Uarrocir:"⥉",Ubrcy:"Ў",ubrcy:"ў",Ubreve:"Ŭ",ubreve:"ŭ",Ucirc:"Û",ucirc:"û",Ucy:"У",ucy:"у",udarr:"⇅",Udblac:"Ű",udblac:"ű",udhar:"⥮",ufisht:"⥾",Ufr:"𝔘",ufr:"𝔲",Ugrave:"Ù",ugrave:"ù",uHar:"⥣",uharl:"↿",uharr:"↾",uhblk:"▀",ulcorn:"⌜",ulcorner:"⌜",ulcrop:"⌏",ultri:"◸",Umacr:"Ū",umacr:"ū",uml:"¨",UnderBar:"_",UnderBrace:"⏟",UnderBracket:"⎵",UnderParenthesis:"⏝",Union:"⋃",UnionPlus:"⊎",Uogon:"Ų",uogon:"ų",Uopf:"𝕌",uopf:"𝕦",UpArrowBar:"⤒",uparrow:"↑",UpArrow:"↑",Uparrow:"⇑",UpArrowDownArrow:"⇅",updownarrow:"↕",UpDownArrow:"↕",Updownarrow:"⇕",UpEquilibrium:"⥮",upharpoonleft:"↿",upharpoonright:"↾",uplus:"⊎",UpperLeftArrow:"↖",UpperRightArrow:"↗",upsi:"υ",Upsi:"ϒ",upsih:"ϒ",Upsilon:"Υ",upsilon:"υ",UpTeeArrow:"↥",UpTee:"⊥",upuparrows:"⇈",urcorn:"⌝",urcorner:"⌝",urcrop:"⌎",Uring:"Ů",uring:"ů",urtri:"◹",Uscr:"𝒰",uscr:"𝓊",utdot:"⋰",Utilde:"Ũ",utilde:"ũ",utri:"▵",utrif:"▴",uuarr:"⇈",Uuml:"Ü",uuml:"ü",uwangle:"⦧",vangrt:"⦜",varepsilon:"ϵ",varkappa:"ϰ",varnothing:"∅",varphi:"ϕ",varpi:"ϖ",varpropto:"∝",varr:"↕",vArr:"⇕",varrho:"ϱ",varsigma:"ς",varsubsetneq:"⊊︀",varsubsetneqq:"⫋︀",varsupsetneq:"⊋︀",varsupsetneqq:"⫌︀",vartheta:"ϑ",vartriangleleft:"⊲",vartriangleright:"⊳",vBar:"⫨",Vbar:"⫫",vBarv:"⫩",Vcy:"В",vcy:"в",vdash:"⊢",vDash:"⊨",Vdash:"⊩",VDash:"⊫",Vdashl:"⫦",veebar:"⊻",vee:"∨",Vee:"⋁",veeeq:"≚",vellip:"⋮",verbar:"|",Verbar:"‖",vert:"|",Vert:"‖",VerticalBar:"∣",VerticalLine:"|",VerticalSeparator:"❘",VerticalTilde:"≀",VeryThinSpace:" ",Vfr:"𝔙",vfr:"𝔳",vltri:"⊲",vnsub:"⊂⃒",vnsup:"⊃⃒",Vopf:"𝕍",vopf:"𝕧",vprop:"∝",vrtri:"⊳",Vscr:"𝒱",vscr:"𝓋",vsubnE:"⫋︀",vsubne:"⊊︀",vsupnE:"⫌︀",vsupne:"⊋︀",Vvdash:"⊪",vzigzag:"⦚",Wcirc:"Ŵ",wcirc:"ŵ",wedbar:"⩟",wedge:"∧",Wedge:"⋀",wedgeq:"≙",weierp:"℘",Wfr:"𝔚",wfr:"𝔴",Wopf:"𝕎",wopf:"𝕨",wp:"℘",wr:"≀",wreath:"≀",Wscr:"𝒲",wscr:"𝓌",xcap:"⋂",xcirc:"◯",xcup:"⋃",xdtri:"▽",Xfr:"𝔛",xfr:"𝔵",xharr:"⟷",xhArr:"⟺",Xi:"Ξ",xi:"ξ",xlarr:"⟵",xlArr:"⟸",xmap:"⟼",xnis:"⋻",xodot:"⨀",Xopf:"𝕏",xopf:"𝕩",xoplus:"⨁",xotime:"⨂",xrarr:"⟶",xrArr:"⟹",Xscr:"𝒳",xscr:"𝓍",xsqcup:"⨆",xuplus:"⨄",xutri:"△",xvee:"⋁",xwedge:"⋀",Yacute:"Ý",yacute:"ý",YAcy:"Я",yacy:"я",Ycirc:"Ŷ",ycirc:"ŷ",Ycy:"Ы",ycy:"ы",yen:"¥",Yfr:"𝔜",yfr:"𝔶",YIcy:"Ї",yicy:"ї",Yopf:"𝕐",yopf:"𝕪",Yscr:"𝒴",yscr:"𝓎",YUcy:"Ю",yucy:"ю",yuml:"ÿ",Yuml:"Ÿ",Zacute:"Ź",zacute:"ź",Zcaron:"Ž",zcaron:"ž",Zcy:"З",zcy:"з",Zdot:"Ż",zdot:"ż",zeetrf:"ℨ",ZeroWidthSpace:"​",Zeta:"Ζ",zeta:"ζ",zfr:"𝔷",Zfr:"ℨ",ZHcy:"Ж",zhcy:"ж",zigrarr:"⇝",zopf:"𝕫",Zopf:"ℤ",Zscr:"𝒵",zscr:"𝓏",zwj:"‍",zwnj:"‌"}},{}],21:[function(t,e,r){e.exports={Aacute:"Á",aacute:"á",Acirc:"Â",acirc:"â",acute:"´",AElig:"Æ",aelig:"æ",Agrave:"À",agrave:"à",amp:"&",AMP:"&",Aring:"Å",aring:"å",Atilde:"Ã",atilde:"ã",Auml:"Ä",auml:"ä",brvbar:"¦",Ccedil:"Ç",ccedil:"ç",cedil:"¸",cent:"¢",copy:"©",COPY:"©",curren:"¤",deg:"°",divide:"÷",Eacute:"É",eacute:"é",Ecirc:"Ê",ecirc:"ê",Egrave:"È",egrave:"è",ETH:"Ð",eth:"ð",Euml:"Ë",euml:"ë",frac12:"½",frac14:"¼",frac34:"¾",gt:">",GT:">",Iacute:"Í",iacute:"í",Icirc:"Î",icirc:"î",iexcl:"¡",Igrave:"Ì",igrave:"ì",iquest:"¿",Iuml:"Ï",iuml:"ï",laquo:"«",lt:"<",LT:"<",macr:"¯",micro:"µ",middot:"·",nbsp:" ",not:"¬",Ntilde:"Ñ",ntilde:"ñ",Oacute:"Ó",oacute:"ó",Ocirc:"Ô",ocirc:"ô",Ograve:"Ò",ograve:"ò",ordf:"ª",ordm:"º",Oslash:"Ø",oslash:"ø",Otilde:"Õ",otilde:"õ",Ouml:"Ö",ouml:"ö",para:"¶",plusmn:"±",pound:"£",quot:'"',QUOT:'"',raquo:"»",reg:"®",REG:"®",sect:"§",shy:"­",sup1:"¹",sup2:"²",sup3:"³",szlig:"ß",THORN:"Þ",thorn:"þ",times:"×",Uacute:"Ú",uacute:"ú",Ucirc:"Û",ucirc:"û",Ugrave:"Ù",ugrave:"ù",uml:"¨",Uuml:"Ü",uuml:"ü",Yacute:"Ý",yacute:"ý",yen:"¥",yuml:"ÿ"}},{}],22:[function(t,e,r){e.exports={amp:"&",apos:"'",gt:">",lt:"<",quot:'"'}},{}],23:[function(t,e,r){e.exports={Text:"text",Directive:"directive",Comment:"comment",Script:"script",Style:"style",Tag:"tag",CDATA:"cdata",Doctype:"doctype",isTag:function(t){return"tag"===t.type||"script"===t.type||"style"===t.type}}},{}],24:[function(t,e,r){var n=t("domelementtype"),i=/\s+/g,o=t("./lib/node"),s=t("./lib/element");function a(t,e,r){"object"==typeof t?(r=e,e=t,t=null):"function"==typeof e&&(r=e,e=c),this._callback=t,this._options=e||c,this._elementCB=r,this.dom=[],this._done=!1,this._tagStack=[],this._parser=this._parser||null}var c={normalizeWhitespace:!1,withStartIndices:!1,withEndIndices:!1};a.prototype.onparserinit=function(t){this._parser=t},a.prototype.onreset=function(){a.call(this,this._callback,this._options,this._elementCB)},a.prototype.onend=function(){this._done||(this._done=!0,this._parser=null,this._handleCallback(null))},a.prototype._handleCallback=a.prototype.onerror=function(t){if("function"==typeof this._callback)this._callback(t,this.dom);else if(t)throw t},a.prototype.onclosetag=function(){var t=this._tagStack.pop();this._options.withEndIndices&&t&&(t.endIndex=this._parser.endIndex),this._elementCB&&this._elementCB(t)},a.prototype._createDomElement=function(t){if(!this._options.withDomLvl1)return t;var e;for(var r in e="tag"===t.type?Object.create(s):Object.create(o),t)t.hasOwnProperty(r)&&(e[r]=t[r]);return e},a.prototype._addDomElement=function(t){var e=this._tagStack[this._tagStack.length-1],r=e?e.children:this.dom,n=r[r.length-1];t.next=null,this._options.withStartIndices&&(t.startIndex=this._parser.startIndex),this._options.withEndIndices&&(t.endIndex=this._parser.endIndex),n?(t.prev=n,n.next=t):t.prev=null,r.push(t),t.parent=e||null},a.prototype.onopentag=function(t,e){var r={type:"script"===t?n.Script:"style"===t?n.Style:n.Tag,name:t,attribs:e,children:[]},i=this._createDomElement(r);this._addDomElement(i),this._tagStack.push(i)},a.prototype.ontext=function(t){var e,r=this._options.normalizeWhitespace||this._options.ignoreWhitespace;if(!this._tagStack.length&&this.dom.length&&(e=this.dom[this.dom.length-1]).type===n.Text)r?e.data=(e.data+t).replace(i," "):e.data+=t;else if(this._tagStack.length&&(e=this._tagStack[this._tagStack.length-1])&&(e=e.children[e.children.length-1])&&e.type===n.Text)r?e.data=(e.data+t).replace(i," "):e.data+=t;else{r&&(t=t.replace(i," "));var o=this._createDomElement({data:t,type:n.Text});this._addDomElement(o)}},a.prototype.oncomment=function(t){var e=this._tagStack[this._tagStack.length-1];if(e&&e.type===n.Comment)e.data+=t;else{var r={data:t,type:n.Comment},i=this._createDomElement(r);this._addDomElement(i),this._tagStack.push(i)}},a.prototype.oncdatastart=function(){var t={children:[{data:"",type:n.Text}],type:n.CDATA},e=this._createDomElement(t);this._addDomElement(e),this._tagStack.push(e)},a.prototype.oncommentend=a.prototype.oncdataend=function(){this._tagStack.pop()},a.prototype.onprocessinginstruction=function(t,e){var r=this._createDomElement({name:t,data:e,type:n.Directive});this._addDomElement(r)},e.exports=a},{"./lib/element":25,"./lib/node":26,domelementtype:23}],25:[function(t,e,r){var n=t("./node"),i=e.exports=Object.create(n),o={tagName:"name"};Object.keys(o).forEach((function(t){var e=o[t];Object.defineProperty(i,t,{get:function(){return this[e]||null},set:function(t){return this[e]=t,t}})}))},{"./node":26}],26:[function(t,e,r){var n=e.exports={get firstChild(){var t=this.children;return t&&t[0]||null},get lastChild(){var t=this.children;return t&&t[t.length-1]||null},get nodeType(){return o[this.type]||o.element}},i={tagName:"name",childNodes:"children",parentNode:"parent",previousSibling:"prev",nextSibling:"next",nodeValue:"data"},o={element:1,text:3,cdata:4,comment:8};Object.keys(i).forEach((function(t){var e=i[t];Object.defineProperty(n,t,{get:function(){return this[e]||null},set:function(t){return this[e]=t,t}})}))},{}],27:[function(t,e,r){var n=e.exports;[t("./lib/stringify"),t("./lib/traversal"),t("./lib/manipulation"),t("./lib/querying"),t("./lib/legacy"),t("./lib/helpers")].forEach((function(t){Object.keys(t).forEach((function(e){n[e]=t[e].bind(n)}))}))},{"./lib/helpers":28,"./lib/legacy":29,"./lib/manipulation":30,"./lib/querying":31,"./lib/stringify":32,"./lib/traversal":33}],28:[function(t,e,r){r.removeSubsets=function(t){for(var e,r,n,i=t.length;--i>-1;){for(e=r=t[i],t[i]=null,n=!0;r;){if(t.indexOf(r)>-1){n=!1,t.splice(i,1);break}r=r.parent}n&&(t[i]=e)}return t};var n=1,i=2,o=4,s=8,a=16,c=r.compareDocumentPosition=function(t,e){var r,c,u,l,p,h,f=[],d=[];if(t===e)return 0;for(r=t;r;)f.unshift(r),r=r.parent;for(r=e;r;)d.unshift(r),r=r.parent;for(h=0;f[h]===d[h];)h++;return 0===h?n:(u=(c=f[h-1]).children,l=f[h],p=d[h],u.indexOf(l)>u.indexOf(p)?c===e?o|a:o:c===t?i|s:i)};r.uniqueSort=function(t){var e,r,n=t.length;for(t=t.slice();--n>-1;)e=t[n],(r=t.indexOf(e))>-1&&r0&&(o=i(t,o,r,n),s=s.concat(o),(n-=o.length)<=0)));a++);return s}e.exports={filter:function(t,e,r,n){Array.isArray(e)||(e=[e]);"number"==typeof n&&isFinite(n)||(n=1/0);return i(t,e,!1!==r,n)},find:i,findOneChild:function(t,e){for(var r=0,n=e.length;r0&&(i=t(e,r[o].children)));return i},existsOne:function t(e,r){for(var i=0,o=r.length;i0&&t(e,r[i].children)))return!0;return!1},findAll:function(t,e){var r=[],i=e.slice();for(;i.length;){var o=i.shift();n(o)&&(o.children&&o.children.length>0&&i.unshift.apply(i,o.children),t(o)&&r.push(o))}return r}}},{domelementtype:23}],32:[function(t,e,r){var n=t("domelementtype"),i=t("dom-serializer"),o=n.isTag;e.exports={getInnerHTML:function(t,e){return t.children?t.children.map((function(t){return i(t,e)})).join(""):""},getOuterHTML:i,getText:function t(e){return Array.isArray(e)?e.map(t).join(""):o(e)?"br"===e.name?"\n":t(e.children):e.type===n.CDATA?t(e.children):e.type===n.Text?e.data:""}}},{"dom-serializer":13,domelementtype:23}],33:[function(t,e,r){var n=r.getChildren=function(t){return t.children},i=r.getParent=function(t){return t.parent};r.getSiblings=function(t){var e=i(t);return e?n(e):[t]},r.getAttributeValue=function(t,e){return t.attribs&&t.attribs[e]},r.hasAttrib=function(t,e){return!!t.attribs&&hasOwnProperty.call(t.attribs,e)},r.getName=function(t){return t.name}},{}],34:[function(t,e,r){var n=t("../maps/decode.json");e.exports=function(t){if(t>=55296&&t<=57343||t>1114111)return"�";t in n&&(t=n[t]);var e="";t>65535&&(t-=65536,e+=String.fromCharCode(t>>>10&1023|55296),t=56320|1023&t);return e+=String.fromCharCode(t)}},{"../maps/decode.json":35}],35:[function(t,e,r){e.exports={0:65533,128:8364,130:8218,131:402,132:8222,133:8230,134:8224,135:8225,136:710,137:8240,138:352,139:8249,140:338,142:381,145:8216,146:8217,147:8220,148:8221,149:8226,150:8211,151:8212,152:732,153:8482,154:353,155:8250,156:339,158:382,159:376}},{}],36:[function(t,e,r){e.exports={Aacute:"Á",aacute:"á",Abreve:"Ă",abreve:"ă",ac:"∾",acd:"∿",acE:"∾̳",Acirc:"Â",acirc:"â",acute:"´",Acy:"А",acy:"а",AElig:"Æ",aelig:"æ",af:"⁡",Afr:"𝔄",afr:"𝔞",Agrave:"À",agrave:"à",alefsym:"ℵ",aleph:"ℵ",Alpha:"Α",alpha:"α",Amacr:"Ā",amacr:"ā",amalg:"⨿",amp:"&",AMP:"&",andand:"⩕",And:"⩓",and:"∧",andd:"⩜",andslope:"⩘",andv:"⩚",ang:"∠",ange:"⦤",angle:"∠",angmsdaa:"⦨",angmsdab:"⦩",angmsdac:"⦪",angmsdad:"⦫",angmsdae:"⦬",angmsdaf:"⦭",angmsdag:"⦮",angmsdah:"⦯",angmsd:"∡",angrt:"∟",angrtvb:"⊾",angrtvbd:"⦝",angsph:"∢",angst:"Å",angzarr:"⍼",Aogon:"Ą",aogon:"ą",Aopf:"𝔸",aopf:"𝕒",apacir:"⩯",ap:"≈",apE:"⩰",ape:"≊",apid:"≋",apos:"'",ApplyFunction:"⁡",approx:"≈",approxeq:"≊",Aring:"Å",aring:"å",Ascr:"𝒜",ascr:"𝒶",Assign:"≔",ast:"*",asymp:"≈",asympeq:"≍",Atilde:"Ã",atilde:"ã",Auml:"Ä",auml:"ä",awconint:"∳",awint:"⨑",backcong:"≌",backepsilon:"϶",backprime:"‵",backsim:"∽",backsimeq:"⋍",Backslash:"∖",Barv:"⫧",barvee:"⊽",barwed:"⌅",Barwed:"⌆",barwedge:"⌅",bbrk:"⎵",bbrktbrk:"⎶",bcong:"≌",Bcy:"Б",bcy:"б",bdquo:"„",becaus:"∵",because:"∵",Because:"∵",bemptyv:"⦰",bepsi:"϶",bernou:"ℬ",Bernoullis:"ℬ",Beta:"Β",beta:"β",beth:"ℶ",between:"≬",Bfr:"𝔅",bfr:"𝔟",bigcap:"⋂",bigcirc:"◯",bigcup:"⋃",bigodot:"⨀",bigoplus:"⨁",bigotimes:"⨂",bigsqcup:"⨆",bigstar:"★",bigtriangledown:"▽",bigtriangleup:"△",biguplus:"⨄",bigvee:"⋁",bigwedge:"⋀",bkarow:"⤍",blacklozenge:"⧫",blacksquare:"▪",blacktriangle:"▴",blacktriangledown:"▾",blacktriangleleft:"◂",blacktriangleright:"▸",blank:"␣",blk12:"▒",blk14:"░",blk34:"▓",block:"█",bne:"=⃥",bnequiv:"≡⃥",bNot:"⫭",bnot:"⌐",Bopf:"𝔹",bopf:"𝕓",bot:"⊥",bottom:"⊥",bowtie:"⋈",boxbox:"⧉",boxdl:"┐",boxdL:"╕",boxDl:"╖",boxDL:"╗",boxdr:"┌",boxdR:"╒",boxDr:"╓",boxDR:"╔",boxh:"─",boxH:"═",boxhd:"┬",boxHd:"╤",boxhD:"╥",boxHD:"╦",boxhu:"┴",boxHu:"╧",boxhU:"╨",boxHU:"╩",boxminus:"⊟",boxplus:"⊞",boxtimes:"⊠",boxul:"┘",boxuL:"╛",boxUl:"╜",boxUL:"╝",boxur:"└",boxuR:"╘",boxUr:"╙",boxUR:"╚",boxv:"│",boxV:"║",boxvh:"┼",boxvH:"╪",boxVh:"╫",boxVH:"╬",boxvl:"┤",boxvL:"╡",boxVl:"╢",boxVL:"╣",boxvr:"├",boxvR:"╞",boxVr:"╟",boxVR:"╠",bprime:"‵",breve:"˘",Breve:"˘",brvbar:"¦",bscr:"𝒷",Bscr:"ℬ",bsemi:"⁏",bsim:"∽",bsime:"⋍",bsolb:"⧅",bsol:"\\",bsolhsub:"⟈",bull:"•",bullet:"•",bump:"≎",bumpE:"⪮",bumpe:"≏",Bumpeq:"≎",bumpeq:"≏",Cacute:"Ć",cacute:"ć",capand:"⩄",capbrcup:"⩉",capcap:"⩋",cap:"∩",Cap:"⋒",capcup:"⩇",capdot:"⩀",CapitalDifferentialD:"ⅅ",caps:"∩︀",caret:"⁁",caron:"ˇ",Cayleys:"ℭ",ccaps:"⩍",Ccaron:"Č",ccaron:"č",Ccedil:"Ç",ccedil:"ç",Ccirc:"Ĉ",ccirc:"ĉ",Cconint:"∰",ccups:"⩌",ccupssm:"⩐",Cdot:"Ċ",cdot:"ċ",cedil:"¸",Cedilla:"¸",cemptyv:"⦲",cent:"¢",centerdot:"·",CenterDot:"·",cfr:"𝔠",Cfr:"ℭ",CHcy:"Ч",chcy:"ч",check:"✓",checkmark:"✓",Chi:"Χ",chi:"χ",circ:"ˆ",circeq:"≗",circlearrowleft:"↺",circlearrowright:"↻",circledast:"⊛",circledcirc:"⊚",circleddash:"⊝",CircleDot:"⊙",circledR:"®",circledS:"Ⓢ",CircleMinus:"⊖",CirclePlus:"⊕",CircleTimes:"⊗",cir:"○",cirE:"⧃",cire:"≗",cirfnint:"⨐",cirmid:"⫯",cirscir:"⧂",ClockwiseContourIntegral:"∲",CloseCurlyDoubleQuote:"”",CloseCurlyQuote:"’",clubs:"♣",clubsuit:"♣",colon:":",Colon:"∷",Colone:"⩴",colone:"≔",coloneq:"≔",comma:",",commat:"@",comp:"∁",compfn:"∘",complement:"∁",complexes:"ℂ",cong:"≅",congdot:"⩭",Congruent:"≡",conint:"∮",Conint:"∯",ContourIntegral:"∮",copf:"𝕔",Copf:"ℂ",coprod:"∐",Coproduct:"∐",copy:"©",COPY:"©",copysr:"℗",CounterClockwiseContourIntegral:"∳",crarr:"↵",cross:"✗",Cross:"⨯",Cscr:"𝒞",cscr:"𝒸",csub:"⫏",csube:"⫑",csup:"⫐",csupe:"⫒",ctdot:"⋯",cudarrl:"⤸",cudarrr:"⤵",cuepr:"⋞",cuesc:"⋟",cularr:"↶",cularrp:"⤽",cupbrcap:"⩈",cupcap:"⩆",CupCap:"≍",cup:"∪",Cup:"⋓",cupcup:"⩊",cupdot:"⊍",cupor:"⩅",cups:"∪︀",curarr:"↷",curarrm:"⤼",curlyeqprec:"⋞",curlyeqsucc:"⋟",curlyvee:"⋎",curlywedge:"⋏",curren:"¤",curvearrowleft:"↶",curvearrowright:"↷",cuvee:"⋎",cuwed:"⋏",cwconint:"∲",cwint:"∱",cylcty:"⌭",dagger:"†",Dagger:"‡",daleth:"ℸ",darr:"↓",Darr:"↡",dArr:"⇓",dash:"‐",Dashv:"⫤",dashv:"⊣",dbkarow:"⤏",dblac:"˝",Dcaron:"Ď",dcaron:"ď",Dcy:"Д",dcy:"д",ddagger:"‡",ddarr:"⇊",DD:"ⅅ",dd:"ⅆ",DDotrahd:"⤑",ddotseq:"⩷",deg:"°",Del:"∇",Delta:"Δ",delta:"δ",demptyv:"⦱",dfisht:"⥿",Dfr:"𝔇",dfr:"𝔡",dHar:"⥥",dharl:"⇃",dharr:"⇂",DiacriticalAcute:"´",DiacriticalDot:"˙",DiacriticalDoubleAcute:"˝",DiacriticalGrave:"`",DiacriticalTilde:"˜",diam:"⋄",diamond:"⋄",Diamond:"⋄",diamondsuit:"♦",diams:"♦",die:"¨",DifferentialD:"ⅆ",digamma:"ϝ",disin:"⋲",div:"÷",divide:"÷",divideontimes:"⋇",divonx:"⋇",DJcy:"Ђ",djcy:"ђ",dlcorn:"⌞",dlcrop:"⌍",dollar:"$",Dopf:"𝔻",dopf:"𝕕",Dot:"¨",dot:"˙",DotDot:"⃜",doteq:"≐",doteqdot:"≑",DotEqual:"≐",dotminus:"∸",dotplus:"∔",dotsquare:"⊡",doublebarwedge:"⌆",DoubleContourIntegral:"∯",DoubleDot:"¨",DoubleDownArrow:"⇓",DoubleLeftArrow:"⇐",DoubleLeftRightArrow:"⇔",DoubleLeftTee:"⫤",DoubleLongLeftArrow:"⟸",DoubleLongLeftRightArrow:"⟺",DoubleLongRightArrow:"⟹",DoubleRightArrow:"⇒",DoubleRightTee:"⊨",DoubleUpArrow:"⇑",DoubleUpDownArrow:"⇕",DoubleVerticalBar:"∥",DownArrowBar:"⤓",downarrow:"↓",DownArrow:"↓",Downarrow:"⇓",DownArrowUpArrow:"⇵",DownBreve:"̑",downdownarrows:"⇊",downharpoonleft:"⇃",downharpoonright:"⇂",DownLeftRightVector:"⥐",DownLeftTeeVector:"⥞",DownLeftVectorBar:"⥖",DownLeftVector:"↽",DownRightTeeVector:"⥟",DownRightVectorBar:"⥗",DownRightVector:"⇁",DownTeeArrow:"↧",DownTee:"⊤",drbkarow:"⤐",drcorn:"⌟",drcrop:"⌌",Dscr:"𝒟",dscr:"𝒹",DScy:"Ѕ",dscy:"ѕ",dsol:"⧶",Dstrok:"Đ",dstrok:"đ",dtdot:"⋱",dtri:"▿",dtrif:"▾",duarr:"⇵",duhar:"⥯",dwangle:"⦦",DZcy:"Џ",dzcy:"џ",dzigrarr:"⟿",Eacute:"É",eacute:"é",easter:"⩮",Ecaron:"Ě",ecaron:"ě",Ecirc:"Ê",ecirc:"ê",ecir:"≖",ecolon:"≕",Ecy:"Э",ecy:"э",eDDot:"⩷",Edot:"Ė",edot:"ė",eDot:"≑",ee:"ⅇ",efDot:"≒",Efr:"𝔈",efr:"𝔢",eg:"⪚",Egrave:"È",egrave:"è",egs:"⪖",egsdot:"⪘",el:"⪙",Element:"∈",elinters:"⏧",ell:"ℓ",els:"⪕",elsdot:"⪗",Emacr:"Ē",emacr:"ē",empty:"∅",emptyset:"∅",EmptySmallSquare:"◻",emptyv:"∅",EmptyVerySmallSquare:"▫",emsp13:" ",emsp14:" ",emsp:" ",ENG:"Ŋ",eng:"ŋ",ensp:" ",Eogon:"Ę",eogon:"ę",Eopf:"𝔼",eopf:"𝕖",epar:"⋕",eparsl:"⧣",eplus:"⩱",epsi:"ε",Epsilon:"Ε",epsilon:"ε",epsiv:"ϵ",eqcirc:"≖",eqcolon:"≕",eqsim:"≂",eqslantgtr:"⪖",eqslantless:"⪕",Equal:"⩵",equals:"=",EqualTilde:"≂",equest:"≟",Equilibrium:"⇌",equiv:"≡",equivDD:"⩸",eqvparsl:"⧥",erarr:"⥱",erDot:"≓",escr:"ℯ",Escr:"ℰ",esdot:"≐",Esim:"⩳",esim:"≂",Eta:"Η",eta:"η",ETH:"Ð",eth:"ð",Euml:"Ë",euml:"ë",euro:"€",excl:"!",exist:"∃",Exists:"∃",expectation:"ℰ",exponentiale:"ⅇ",ExponentialE:"ⅇ",fallingdotseq:"≒",Fcy:"Ф",fcy:"ф",female:"♀",ffilig:"ffi",fflig:"ff",ffllig:"ffl",Ffr:"𝔉",ffr:"𝔣",filig:"fi",FilledSmallSquare:"◼",FilledVerySmallSquare:"▪",fjlig:"fj",flat:"♭",fllig:"fl",fltns:"▱",fnof:"ƒ",Fopf:"𝔽",fopf:"𝕗",forall:"∀",ForAll:"∀",fork:"⋔",forkv:"⫙",Fouriertrf:"ℱ",fpartint:"⨍",frac12:"½",frac13:"⅓",frac14:"¼",frac15:"⅕",frac16:"⅙",frac18:"⅛",frac23:"⅔",frac25:"⅖",frac34:"¾",frac35:"⅗",frac38:"⅜",frac45:"⅘",frac56:"⅚",frac58:"⅝",frac78:"⅞",frasl:"⁄",frown:"⌢",fscr:"𝒻",Fscr:"ℱ",gacute:"ǵ",Gamma:"Γ",gamma:"γ",Gammad:"Ϝ",gammad:"ϝ",gap:"⪆",Gbreve:"Ğ",gbreve:"ğ",Gcedil:"Ģ",Gcirc:"Ĝ",gcirc:"ĝ",Gcy:"Г",gcy:"г",Gdot:"Ġ",gdot:"ġ",ge:"≥",gE:"≧",gEl:"⪌",gel:"⋛",geq:"≥",geqq:"≧",geqslant:"⩾",gescc:"⪩",ges:"⩾",gesdot:"⪀",gesdoto:"⪂",gesdotol:"⪄",gesl:"⋛︀",gesles:"⪔",Gfr:"𝔊",gfr:"𝔤",gg:"≫",Gg:"⋙",ggg:"⋙",gimel:"ℷ",GJcy:"Ѓ",gjcy:"ѓ",gla:"⪥",gl:"≷",glE:"⪒",glj:"⪤",gnap:"⪊",gnapprox:"⪊",gne:"⪈",gnE:"≩",gneq:"⪈",gneqq:"≩",gnsim:"⋧",Gopf:"𝔾",gopf:"𝕘",grave:"`",GreaterEqual:"≥",GreaterEqualLess:"⋛",GreaterFullEqual:"≧",GreaterGreater:"⪢",GreaterLess:"≷",GreaterSlantEqual:"⩾",GreaterTilde:"≳",Gscr:"𝒢",gscr:"ℊ",gsim:"≳",gsime:"⪎",gsiml:"⪐",gtcc:"⪧",gtcir:"⩺",gt:">",GT:">",Gt:"≫",gtdot:"⋗",gtlPar:"⦕",gtquest:"⩼",gtrapprox:"⪆",gtrarr:"⥸",gtrdot:"⋗",gtreqless:"⋛",gtreqqless:"⪌",gtrless:"≷",gtrsim:"≳",gvertneqq:"≩︀",gvnE:"≩︀",Hacek:"ˇ",hairsp:" ",half:"½",hamilt:"ℋ",HARDcy:"Ъ",hardcy:"ъ",harrcir:"⥈",harr:"↔",hArr:"⇔",harrw:"↭",Hat:"^",hbar:"ℏ",Hcirc:"Ĥ",hcirc:"ĥ",hearts:"♥",heartsuit:"♥",hellip:"…",hercon:"⊹",hfr:"𝔥",Hfr:"ℌ",HilbertSpace:"ℋ",hksearow:"⤥",hkswarow:"⤦",hoarr:"⇿",homtht:"∻",hookleftarrow:"↩",hookrightarrow:"↪",hopf:"𝕙",Hopf:"ℍ",horbar:"―",HorizontalLine:"─",hscr:"𝒽",Hscr:"ℋ",hslash:"ℏ",Hstrok:"Ħ",hstrok:"ħ",HumpDownHump:"≎",HumpEqual:"≏",hybull:"⁃",hyphen:"‐",Iacute:"Í",iacute:"í",ic:"⁣",Icirc:"Î",icirc:"î",Icy:"И",icy:"и",Idot:"İ",IEcy:"Е",iecy:"е",iexcl:"¡",iff:"⇔",ifr:"𝔦",Ifr:"ℑ",Igrave:"Ì",igrave:"ì",ii:"ⅈ",iiiint:"⨌",iiint:"∭",iinfin:"⧜",iiota:"℩",IJlig:"IJ",ijlig:"ij",Imacr:"Ī",imacr:"ī",image:"ℑ",ImaginaryI:"ⅈ",imagline:"ℐ",imagpart:"ℑ",imath:"ı",Im:"ℑ",imof:"⊷",imped:"Ƶ",Implies:"⇒",incare:"℅",in:"∈",infin:"∞",infintie:"⧝",inodot:"ı",intcal:"⊺",int:"∫",Int:"∬",integers:"ℤ",Integral:"∫",intercal:"⊺",Intersection:"⋂",intlarhk:"⨗",intprod:"⨼",InvisibleComma:"⁣",InvisibleTimes:"⁢",IOcy:"Ё",iocy:"ё",Iogon:"Į",iogon:"į",Iopf:"𝕀",iopf:"𝕚",Iota:"Ι",iota:"ι",iprod:"⨼",iquest:"¿",iscr:"𝒾",Iscr:"ℐ",isin:"∈",isindot:"⋵",isinE:"⋹",isins:"⋴",isinsv:"⋳",isinv:"∈",it:"⁢",Itilde:"Ĩ",itilde:"ĩ",Iukcy:"І",iukcy:"і",Iuml:"Ï",iuml:"ï",Jcirc:"Ĵ",jcirc:"ĵ",Jcy:"Й",jcy:"й",Jfr:"𝔍",jfr:"𝔧",jmath:"ȷ",Jopf:"𝕁",jopf:"𝕛",Jscr:"𝒥",jscr:"𝒿",Jsercy:"Ј",jsercy:"ј",Jukcy:"Є",jukcy:"є",Kappa:"Κ",kappa:"κ",kappav:"ϰ",Kcedil:"Ķ",kcedil:"ķ",Kcy:"К",kcy:"к",Kfr:"𝔎",kfr:"𝔨",kgreen:"ĸ",KHcy:"Х",khcy:"х",KJcy:"Ќ",kjcy:"ќ",Kopf:"𝕂",kopf:"𝕜",Kscr:"𝒦",kscr:"𝓀",lAarr:"⇚",Lacute:"Ĺ",lacute:"ĺ",laemptyv:"⦴",lagran:"ℒ",Lambda:"Λ",lambda:"λ",lang:"⟨",Lang:"⟪",langd:"⦑",langle:"⟨",lap:"⪅",Laplacetrf:"ℒ",laquo:"«",larrb:"⇤",larrbfs:"⤟",larr:"←",Larr:"↞",lArr:"⇐",larrfs:"⤝",larrhk:"↩",larrlp:"↫",larrpl:"⤹",larrsim:"⥳",larrtl:"↢",latail:"⤙",lAtail:"⤛",lat:"⪫",late:"⪭",lates:"⪭︀",lbarr:"⤌",lBarr:"⤎",lbbrk:"❲",lbrace:"{",lbrack:"[",lbrke:"⦋",lbrksld:"⦏",lbrkslu:"⦍",Lcaron:"Ľ",lcaron:"ľ",Lcedil:"Ļ",lcedil:"ļ",lceil:"⌈",lcub:"{",Lcy:"Л",lcy:"л",ldca:"⤶",ldquo:"“",ldquor:"„",ldrdhar:"⥧",ldrushar:"⥋",ldsh:"↲",le:"≤",lE:"≦",LeftAngleBracket:"⟨",LeftArrowBar:"⇤",leftarrow:"←",LeftArrow:"←",Leftarrow:"⇐",LeftArrowRightArrow:"⇆",leftarrowtail:"↢",LeftCeiling:"⌈",LeftDoubleBracket:"⟦",LeftDownTeeVector:"⥡",LeftDownVectorBar:"⥙",LeftDownVector:"⇃",LeftFloor:"⌊",leftharpoondown:"↽",leftharpoonup:"↼",leftleftarrows:"⇇",leftrightarrow:"↔",LeftRightArrow:"↔",Leftrightarrow:"⇔",leftrightarrows:"⇆",leftrightharpoons:"⇋",leftrightsquigarrow:"↭",LeftRightVector:"⥎",LeftTeeArrow:"↤",LeftTee:"⊣",LeftTeeVector:"⥚",leftthreetimes:"⋋",LeftTriangleBar:"⧏",LeftTriangle:"⊲",LeftTriangleEqual:"⊴",LeftUpDownVector:"⥑",LeftUpTeeVector:"⥠",LeftUpVectorBar:"⥘",LeftUpVector:"↿",LeftVectorBar:"⥒",LeftVector:"↼",lEg:"⪋",leg:"⋚",leq:"≤",leqq:"≦",leqslant:"⩽",lescc:"⪨",les:"⩽",lesdot:"⩿",lesdoto:"⪁",lesdotor:"⪃",lesg:"⋚︀",lesges:"⪓",lessapprox:"⪅",lessdot:"⋖",lesseqgtr:"⋚",lesseqqgtr:"⪋",LessEqualGreater:"⋚",LessFullEqual:"≦",LessGreater:"≶",lessgtr:"≶",LessLess:"⪡",lesssim:"≲",LessSlantEqual:"⩽",LessTilde:"≲",lfisht:"⥼",lfloor:"⌊",Lfr:"𝔏",lfr:"𝔩",lg:"≶",lgE:"⪑",lHar:"⥢",lhard:"↽",lharu:"↼",lharul:"⥪",lhblk:"▄",LJcy:"Љ",ljcy:"љ",llarr:"⇇",ll:"≪",Ll:"⋘",llcorner:"⌞",Lleftarrow:"⇚",llhard:"⥫",lltri:"◺",Lmidot:"Ŀ",lmidot:"ŀ",lmoustache:"⎰",lmoust:"⎰",lnap:"⪉",lnapprox:"⪉",lne:"⪇",lnE:"≨",lneq:"⪇",lneqq:"≨",lnsim:"⋦",loang:"⟬",loarr:"⇽",lobrk:"⟦",longleftarrow:"⟵",LongLeftArrow:"⟵",Longleftarrow:"⟸",longleftrightarrow:"⟷",LongLeftRightArrow:"⟷",Longleftrightarrow:"⟺",longmapsto:"⟼",longrightarrow:"⟶",LongRightArrow:"⟶",Longrightarrow:"⟹",looparrowleft:"↫",looparrowright:"↬",lopar:"⦅",Lopf:"𝕃",lopf:"𝕝",loplus:"⨭",lotimes:"⨴",lowast:"∗",lowbar:"_",LowerLeftArrow:"↙",LowerRightArrow:"↘",loz:"◊",lozenge:"◊",lozf:"⧫",lpar:"(",lparlt:"⦓",lrarr:"⇆",lrcorner:"⌟",lrhar:"⇋",lrhard:"⥭",lrm:"‎",lrtri:"⊿",lsaquo:"‹",lscr:"𝓁",Lscr:"ℒ",lsh:"↰",Lsh:"↰",lsim:"≲",lsime:"⪍",lsimg:"⪏",lsqb:"[",lsquo:"‘",lsquor:"‚",Lstrok:"Ł",lstrok:"ł",ltcc:"⪦",ltcir:"⩹",lt:"<",LT:"<",Lt:"≪",ltdot:"⋖",lthree:"⋋",ltimes:"⋉",ltlarr:"⥶",ltquest:"⩻",ltri:"◃",ltrie:"⊴",ltrif:"◂",ltrPar:"⦖",lurdshar:"⥊",luruhar:"⥦",lvertneqq:"≨︀",lvnE:"≨︀",macr:"¯",male:"♂",malt:"✠",maltese:"✠",Map:"⤅",map:"↦",mapsto:"↦",mapstodown:"↧",mapstoleft:"↤",mapstoup:"↥",marker:"▮",mcomma:"⨩",Mcy:"М",mcy:"м",mdash:"—",mDDot:"∺",measuredangle:"∡",MediumSpace:" ",Mellintrf:"ℳ",Mfr:"𝔐",mfr:"𝔪",mho:"℧",micro:"µ",midast:"*",midcir:"⫰",mid:"∣",middot:"·",minusb:"⊟",minus:"−",minusd:"∸",minusdu:"⨪",MinusPlus:"∓",mlcp:"⫛",mldr:"…",mnplus:"∓",models:"⊧",Mopf:"𝕄",mopf:"𝕞",mp:"∓",mscr:"𝓂",Mscr:"ℳ",mstpos:"∾",Mu:"Μ",mu:"μ",multimap:"⊸",mumap:"⊸",nabla:"∇",Nacute:"Ń",nacute:"ń",nang:"∠⃒",nap:"≉",napE:"⩰̸",napid:"≋̸",napos:"ʼn",napprox:"≉",natural:"♮",naturals:"ℕ",natur:"♮",nbsp:" ",nbump:"≎̸",nbumpe:"≏̸",ncap:"⩃",Ncaron:"Ň",ncaron:"ň",Ncedil:"Ņ",ncedil:"ņ",ncong:"≇",ncongdot:"⩭̸",ncup:"⩂",Ncy:"Н",ncy:"н",ndash:"–",nearhk:"⤤",nearr:"↗",neArr:"⇗",nearrow:"↗",ne:"≠",nedot:"≐̸",NegativeMediumSpace:"​",NegativeThickSpace:"​",NegativeThinSpace:"​",NegativeVeryThinSpace:"​",nequiv:"≢",nesear:"⤨",nesim:"≂̸",NestedGreaterGreater:"≫",NestedLessLess:"≪",NewLine:"\n",nexist:"∄",nexists:"∄",Nfr:"𝔑",nfr:"𝔫",ngE:"≧̸",nge:"≱",ngeq:"≱",ngeqq:"≧̸",ngeqslant:"⩾̸",nges:"⩾̸",nGg:"⋙̸",ngsim:"≵",nGt:"≫⃒",ngt:"≯",ngtr:"≯",nGtv:"≫̸",nharr:"↮",nhArr:"⇎",nhpar:"⫲",ni:"∋",nis:"⋼",nisd:"⋺",niv:"∋",NJcy:"Њ",njcy:"њ",nlarr:"↚",nlArr:"⇍",nldr:"‥",nlE:"≦̸",nle:"≰",nleftarrow:"↚",nLeftarrow:"⇍",nleftrightarrow:"↮",nLeftrightarrow:"⇎",nleq:"≰",nleqq:"≦̸",nleqslant:"⩽̸",nles:"⩽̸",nless:"≮",nLl:"⋘̸",nlsim:"≴",nLt:"≪⃒",nlt:"≮",nltri:"⋪",nltrie:"⋬",nLtv:"≪̸",nmid:"∤",NoBreak:"⁠",NonBreakingSpace:" ",nopf:"𝕟",Nopf:"ℕ",Not:"⫬",not:"¬",NotCongruent:"≢",NotCupCap:"≭",NotDoubleVerticalBar:"∦",NotElement:"∉",NotEqual:"≠",NotEqualTilde:"≂̸",NotExists:"∄",NotGreater:"≯",NotGreaterEqual:"≱",NotGreaterFullEqual:"≧̸",NotGreaterGreater:"≫̸",NotGreaterLess:"≹",NotGreaterSlantEqual:"⩾̸",NotGreaterTilde:"≵",NotHumpDownHump:"≎̸",NotHumpEqual:"≏̸",notin:"∉",notindot:"⋵̸",notinE:"⋹̸",notinva:"∉",notinvb:"⋷",notinvc:"⋶",NotLeftTriangleBar:"⧏̸",NotLeftTriangle:"⋪",NotLeftTriangleEqual:"⋬",NotLess:"≮",NotLessEqual:"≰",NotLessGreater:"≸",NotLessLess:"≪̸",NotLessSlantEqual:"⩽̸",NotLessTilde:"≴",NotNestedGreaterGreater:"⪢̸",NotNestedLessLess:"⪡̸",notni:"∌",notniva:"∌",notnivb:"⋾",notnivc:"⋽",NotPrecedes:"⊀",NotPrecedesEqual:"⪯̸",NotPrecedesSlantEqual:"⋠",NotReverseElement:"∌",NotRightTriangleBar:"⧐̸",NotRightTriangle:"⋫",NotRightTriangleEqual:"⋭",NotSquareSubset:"⊏̸",NotSquareSubsetEqual:"⋢",NotSquareSuperset:"⊐̸",NotSquareSupersetEqual:"⋣",NotSubset:"⊂⃒",NotSubsetEqual:"⊈",NotSucceeds:"⊁",NotSucceedsEqual:"⪰̸",NotSucceedsSlantEqual:"⋡",NotSucceedsTilde:"≿̸",NotSuperset:"⊃⃒",NotSupersetEqual:"⊉",NotTilde:"≁",NotTildeEqual:"≄",NotTildeFullEqual:"≇",NotTildeTilde:"≉",NotVerticalBar:"∤",nparallel:"∦",npar:"∦",nparsl:"⫽⃥",npart:"∂̸",npolint:"⨔",npr:"⊀",nprcue:"⋠",nprec:"⊀",npreceq:"⪯̸",npre:"⪯̸",nrarrc:"⤳̸",nrarr:"↛",nrArr:"⇏",nrarrw:"↝̸",nrightarrow:"↛",nRightarrow:"⇏",nrtri:"⋫",nrtrie:"⋭",nsc:"⊁",nsccue:"⋡",nsce:"⪰̸",Nscr:"𝒩",nscr:"𝓃",nshortmid:"∤",nshortparallel:"∦",nsim:"≁",nsime:"≄",nsimeq:"≄",nsmid:"∤",nspar:"∦",nsqsube:"⋢",nsqsupe:"⋣",nsub:"⊄",nsubE:"⫅̸",nsube:"⊈",nsubset:"⊂⃒",nsubseteq:"⊈",nsubseteqq:"⫅̸",nsucc:"⊁",nsucceq:"⪰̸",nsup:"⊅",nsupE:"⫆̸",nsupe:"⊉",nsupset:"⊃⃒",nsupseteq:"⊉",nsupseteqq:"⫆̸",ntgl:"≹",Ntilde:"Ñ",ntilde:"ñ",ntlg:"≸",ntriangleleft:"⋪",ntrianglelefteq:"⋬",ntriangleright:"⋫",ntrianglerighteq:"⋭",Nu:"Ν",nu:"ν",num:"#",numero:"№",numsp:" ",nvap:"≍⃒",nvdash:"⊬",nvDash:"⊭",nVdash:"⊮",nVDash:"⊯",nvge:"≥⃒",nvgt:">⃒",nvHarr:"⤄",nvinfin:"⧞",nvlArr:"⤂",nvle:"≤⃒",nvlt:"<⃒",nvltrie:"⊴⃒",nvrArr:"⤃",nvrtrie:"⊵⃒",nvsim:"∼⃒",nwarhk:"⤣",nwarr:"↖",nwArr:"⇖",nwarrow:"↖",nwnear:"⤧",Oacute:"Ó",oacute:"ó",oast:"⊛",Ocirc:"Ô",ocirc:"ô",ocir:"⊚",Ocy:"О",ocy:"о",odash:"⊝",Odblac:"Ő",odblac:"ő",odiv:"⨸",odot:"⊙",odsold:"⦼",OElig:"Œ",oelig:"œ",ofcir:"⦿",Ofr:"𝔒",ofr:"𝔬",ogon:"˛",Ograve:"Ò",ograve:"ò",ogt:"⧁",ohbar:"⦵",ohm:"Ω",oint:"∮",olarr:"↺",olcir:"⦾",olcross:"⦻",oline:"‾",olt:"⧀",Omacr:"Ō",omacr:"ō",Omega:"Ω",omega:"ω",Omicron:"Ο",omicron:"ο",omid:"⦶",ominus:"⊖",Oopf:"𝕆",oopf:"𝕠",opar:"⦷",OpenCurlyDoubleQuote:"“",OpenCurlyQuote:"‘",operp:"⦹",oplus:"⊕",orarr:"↻",Or:"⩔",or:"∨",ord:"⩝",order:"ℴ",orderof:"ℴ",ordf:"ª",ordm:"º",origof:"⊶",oror:"⩖",orslope:"⩗",orv:"⩛",oS:"Ⓢ",Oscr:"𝒪",oscr:"ℴ",Oslash:"Ø",oslash:"ø",osol:"⊘",Otilde:"Õ",otilde:"õ",otimesas:"⨶",Otimes:"⨷",otimes:"⊗",Ouml:"Ö",ouml:"ö",ovbar:"⌽",OverBar:"‾",OverBrace:"⏞",OverBracket:"⎴",OverParenthesis:"⏜",para:"¶",parallel:"∥",par:"∥",parsim:"⫳",parsl:"⫽",part:"∂",PartialD:"∂",Pcy:"П",pcy:"п",percnt:"%",period:".",permil:"‰",perp:"⊥",pertenk:"‱",Pfr:"𝔓",pfr:"𝔭",Phi:"Φ",phi:"φ",phiv:"ϕ",phmmat:"ℳ",phone:"☎",Pi:"Π",pi:"π",pitchfork:"⋔",piv:"ϖ",planck:"ℏ",planckh:"ℎ",plankv:"ℏ",plusacir:"⨣",plusb:"⊞",pluscir:"⨢",plus:"+",plusdo:"∔",plusdu:"⨥",pluse:"⩲",PlusMinus:"±",plusmn:"±",plussim:"⨦",plustwo:"⨧",pm:"±",Poincareplane:"ℌ",pointint:"⨕",popf:"𝕡",Popf:"ℙ",pound:"£",prap:"⪷",Pr:"⪻",pr:"≺",prcue:"≼",precapprox:"⪷",prec:"≺",preccurlyeq:"≼",Precedes:"≺",PrecedesEqual:"⪯",PrecedesSlantEqual:"≼",PrecedesTilde:"≾",preceq:"⪯",precnapprox:"⪹",precneqq:"⪵",precnsim:"⋨",pre:"⪯",prE:"⪳",precsim:"≾",prime:"′",Prime:"″",primes:"ℙ",prnap:"⪹",prnE:"⪵",prnsim:"⋨",prod:"∏",Product:"∏",profalar:"⌮",profline:"⌒",profsurf:"⌓",prop:"∝",Proportional:"∝",Proportion:"∷",propto:"∝",prsim:"≾",prurel:"⊰",Pscr:"𝒫",pscr:"𝓅",Psi:"Ψ",psi:"ψ",puncsp:" ",Qfr:"𝔔",qfr:"𝔮",qint:"⨌",qopf:"𝕢",Qopf:"ℚ",qprime:"⁗",Qscr:"𝒬",qscr:"𝓆",quaternions:"ℍ",quatint:"⨖",quest:"?",questeq:"≟",quot:'"',QUOT:'"',rAarr:"⇛",race:"∽̱",Racute:"Ŕ",racute:"ŕ",radic:"√",raemptyv:"⦳",rang:"⟩",Rang:"⟫",rangd:"⦒",range:"⦥",rangle:"⟩",raquo:"»",rarrap:"⥵",rarrb:"⇥",rarrbfs:"⤠",rarrc:"⤳",rarr:"→",Rarr:"↠",rArr:"⇒",rarrfs:"⤞",rarrhk:"↪",rarrlp:"↬",rarrpl:"⥅",rarrsim:"⥴",Rarrtl:"⤖",rarrtl:"↣",rarrw:"↝",ratail:"⤚",rAtail:"⤜",ratio:"∶",rationals:"ℚ",rbarr:"⤍",rBarr:"⤏",RBarr:"⤐",rbbrk:"❳",rbrace:"}",rbrack:"]",rbrke:"⦌",rbrksld:"⦎",rbrkslu:"⦐",Rcaron:"Ř",rcaron:"ř",Rcedil:"Ŗ",rcedil:"ŗ",rceil:"⌉",rcub:"}",Rcy:"Р",rcy:"р",rdca:"⤷",rdldhar:"⥩",rdquo:"”",rdquor:"”",rdsh:"↳",real:"ℜ",realine:"ℛ",realpart:"ℜ",reals:"ℝ",Re:"ℜ",rect:"▭",reg:"®",REG:"®",ReverseElement:"∋",ReverseEquilibrium:"⇋",ReverseUpEquilibrium:"⥯",rfisht:"⥽",rfloor:"⌋",rfr:"𝔯",Rfr:"ℜ",rHar:"⥤",rhard:"⇁",rharu:"⇀",rharul:"⥬",Rho:"Ρ",rho:"ρ",rhov:"ϱ",RightAngleBracket:"⟩",RightArrowBar:"⇥",rightarrow:"→",RightArrow:"→",Rightarrow:"⇒",RightArrowLeftArrow:"⇄",rightarrowtail:"↣",RightCeiling:"⌉",RightDoubleBracket:"⟧",RightDownTeeVector:"⥝",RightDownVectorBar:"⥕",RightDownVector:"⇂",RightFloor:"⌋",rightharpoondown:"⇁",rightharpoonup:"⇀",rightleftarrows:"⇄",rightleftharpoons:"⇌",rightrightarrows:"⇉",rightsquigarrow:"↝",RightTeeArrow:"↦",RightTee:"⊢",RightTeeVector:"⥛",rightthreetimes:"⋌",RightTriangleBar:"⧐",RightTriangle:"⊳",RightTriangleEqual:"⊵",RightUpDownVector:"⥏",RightUpTeeVector:"⥜",RightUpVectorBar:"⥔",RightUpVector:"↾",RightVectorBar:"⥓",RightVector:"⇀",ring:"˚",risingdotseq:"≓",rlarr:"⇄",rlhar:"⇌",rlm:"‏",rmoustache:"⎱",rmoust:"⎱",rnmid:"⫮",roang:"⟭",roarr:"⇾",robrk:"⟧",ropar:"⦆",ropf:"𝕣",Ropf:"ℝ",roplus:"⨮",rotimes:"⨵",RoundImplies:"⥰",rpar:")",rpargt:"⦔",rppolint:"⨒",rrarr:"⇉",Rrightarrow:"⇛",rsaquo:"›",rscr:"𝓇",Rscr:"ℛ",rsh:"↱",Rsh:"↱",rsqb:"]",rsquo:"’",rsquor:"’",rthree:"⋌",rtimes:"⋊",rtri:"▹",rtrie:"⊵",rtrif:"▸",rtriltri:"⧎",RuleDelayed:"⧴",ruluhar:"⥨",rx:"℞",Sacute:"Ś",sacute:"ś",sbquo:"‚",scap:"⪸",Scaron:"Š",scaron:"š",Sc:"⪼",sc:"≻",sccue:"≽",sce:"⪰",scE:"⪴",Scedil:"Ş",scedil:"ş",Scirc:"Ŝ",scirc:"ŝ",scnap:"⪺",scnE:"⪶",scnsim:"⋩",scpolint:"⨓",scsim:"≿",Scy:"С",scy:"с",sdotb:"⊡",sdot:"⋅",sdote:"⩦",searhk:"⤥",searr:"↘",seArr:"⇘",searrow:"↘",sect:"§",semi:";",seswar:"⤩",setminus:"∖",setmn:"∖",sext:"✶",Sfr:"𝔖",sfr:"𝔰",sfrown:"⌢",sharp:"♯",SHCHcy:"Щ",shchcy:"щ",SHcy:"Ш",shcy:"ш",ShortDownArrow:"↓",ShortLeftArrow:"←",shortmid:"∣",shortparallel:"∥",ShortRightArrow:"→",ShortUpArrow:"↑",shy:"­",Sigma:"Σ",sigma:"σ",sigmaf:"ς",sigmav:"ς",sim:"∼",simdot:"⩪",sime:"≃",simeq:"≃",simg:"⪞",simgE:"⪠",siml:"⪝",simlE:"⪟",simne:"≆",simplus:"⨤",simrarr:"⥲",slarr:"←",SmallCircle:"∘",smallsetminus:"∖",smashp:"⨳",smeparsl:"⧤",smid:"∣",smile:"⌣",smt:"⪪",smte:"⪬",smtes:"⪬︀",SOFTcy:"Ь",softcy:"ь",solbar:"⌿",solb:"⧄",sol:"/",Sopf:"𝕊",sopf:"𝕤",spades:"♠",spadesuit:"♠",spar:"∥",sqcap:"⊓",sqcaps:"⊓︀",sqcup:"⊔",sqcups:"⊔︀",Sqrt:"√",sqsub:"⊏",sqsube:"⊑",sqsubset:"⊏",sqsubseteq:"⊑",sqsup:"⊐",sqsupe:"⊒",sqsupset:"⊐",sqsupseteq:"⊒",square:"□",Square:"□",SquareIntersection:"⊓",SquareSubset:"⊏",SquareSubsetEqual:"⊑",SquareSuperset:"⊐",SquareSupersetEqual:"⊒",SquareUnion:"⊔",squarf:"▪",squ:"□",squf:"▪",srarr:"→",Sscr:"𝒮",sscr:"𝓈",ssetmn:"∖",ssmile:"⌣",sstarf:"⋆",Star:"⋆",star:"☆",starf:"★",straightepsilon:"ϵ",straightphi:"ϕ",strns:"¯",sub:"⊂",Sub:"⋐",subdot:"⪽",subE:"⫅",sube:"⊆",subedot:"⫃",submult:"⫁",subnE:"⫋",subne:"⊊",subplus:"⪿",subrarr:"⥹",subset:"⊂",Subset:"⋐",subseteq:"⊆",subseteqq:"⫅",SubsetEqual:"⊆",subsetneq:"⊊",subsetneqq:"⫋",subsim:"⫇",subsub:"⫕",subsup:"⫓",succapprox:"⪸",succ:"≻",succcurlyeq:"≽",Succeeds:"≻",SucceedsEqual:"⪰",SucceedsSlantEqual:"≽",SucceedsTilde:"≿",succeq:"⪰",succnapprox:"⪺",succneqq:"⪶",succnsim:"⋩",succsim:"≿",SuchThat:"∋",sum:"∑",Sum:"∑",sung:"♪",sup1:"¹",sup2:"²",sup3:"³",sup:"⊃",Sup:"⋑",supdot:"⪾",supdsub:"⫘",supE:"⫆",supe:"⊇",supedot:"⫄",Superset:"⊃",SupersetEqual:"⊇",suphsol:"⟉",suphsub:"⫗",suplarr:"⥻",supmult:"⫂",supnE:"⫌",supne:"⊋",supplus:"⫀",supset:"⊃",Supset:"⋑",supseteq:"⊇",supseteqq:"⫆",supsetneq:"⊋",supsetneqq:"⫌",supsim:"⫈",supsub:"⫔",supsup:"⫖",swarhk:"⤦",swarr:"↙",swArr:"⇙",swarrow:"↙",swnwar:"⤪",szlig:"ß",Tab:"\t",target:"⌖",Tau:"Τ",tau:"τ",tbrk:"⎴",Tcaron:"Ť",tcaron:"ť",Tcedil:"Ţ",tcedil:"ţ",Tcy:"Т",tcy:"т",tdot:"⃛",telrec:"⌕",Tfr:"𝔗",tfr:"𝔱",there4:"∴",therefore:"∴",Therefore:"∴",Theta:"Θ",theta:"θ",thetasym:"ϑ",thetav:"ϑ",thickapprox:"≈",thicksim:"∼",ThickSpace:"  ",ThinSpace:" ",thinsp:" ",thkap:"≈",thksim:"∼",THORN:"Þ",thorn:"þ",tilde:"˜",Tilde:"∼",TildeEqual:"≃",TildeFullEqual:"≅",TildeTilde:"≈",timesbar:"⨱",timesb:"⊠",times:"×",timesd:"⨰",tint:"∭",toea:"⤨",topbot:"⌶",topcir:"⫱",top:"⊤",Topf:"𝕋",topf:"𝕥",topfork:"⫚",tosa:"⤩",tprime:"‴",trade:"™",TRADE:"™",triangle:"▵",triangledown:"▿",triangleleft:"◃",trianglelefteq:"⊴",triangleq:"≜",triangleright:"▹",trianglerighteq:"⊵",tridot:"◬",trie:"≜",triminus:"⨺",TripleDot:"⃛",triplus:"⨹",trisb:"⧍",tritime:"⨻",trpezium:"⏢",Tscr:"𝒯",tscr:"𝓉",TScy:"Ц",tscy:"ц",TSHcy:"Ћ",tshcy:"ћ",Tstrok:"Ŧ",tstrok:"ŧ",twixt:"≬",twoheadleftarrow:"↞",twoheadrightarrow:"↠",Uacute:"Ú",uacute:"ú",uarr:"↑",Uarr:"↟",uArr:"⇑",Uarrocir:"⥉",Ubrcy:"Ў",ubrcy:"ў",Ubreve:"Ŭ",ubreve:"ŭ",Ucirc:"Û",ucirc:"û",Ucy:"У",ucy:"у",udarr:"⇅",Udblac:"Ű",udblac:"ű",udhar:"⥮",ufisht:"⥾",Ufr:"𝔘",ufr:"𝔲",Ugrave:"Ù",ugrave:"ù",uHar:"⥣",uharl:"↿",uharr:"↾",uhblk:"▀",ulcorn:"⌜",ulcorner:"⌜",ulcrop:"⌏",ultri:"◸",Umacr:"Ū",umacr:"ū",uml:"¨",UnderBar:"_",UnderBrace:"⏟",UnderBracket:"⎵",UnderParenthesis:"⏝",Union:"⋃",UnionPlus:"⊎",Uogon:"Ų",uogon:"ų",Uopf:"𝕌",uopf:"𝕦",UpArrowBar:"⤒",uparrow:"↑",UpArrow:"↑",Uparrow:"⇑",UpArrowDownArrow:"⇅",updownarrow:"↕",UpDownArrow:"↕",Updownarrow:"⇕",UpEquilibrium:"⥮",upharpoonleft:"↿",upharpoonright:"↾",uplus:"⊎",UpperLeftArrow:"↖",UpperRightArrow:"↗",upsi:"υ",Upsi:"ϒ",upsih:"ϒ",Upsilon:"Υ",upsilon:"υ",UpTeeArrow:"↥",UpTee:"⊥",upuparrows:"⇈",urcorn:"⌝",urcorner:"⌝",urcrop:"⌎",Uring:"Ů",uring:"ů",urtri:"◹",Uscr:"𝒰",uscr:"𝓊",utdot:"⋰",Utilde:"Ũ",utilde:"ũ",utri:"▵",utrif:"▴",uuarr:"⇈",Uuml:"Ü",uuml:"ü",uwangle:"⦧",vangrt:"⦜",varepsilon:"ϵ",varkappa:"ϰ",varnothing:"∅",varphi:"ϕ",varpi:"ϖ",varpropto:"∝",varr:"↕",vArr:"⇕",varrho:"ϱ",varsigma:"ς",varsubsetneq:"⊊︀",varsubsetneqq:"⫋︀",varsupsetneq:"⊋︀",varsupsetneqq:"⫌︀",vartheta:"ϑ",vartriangleleft:"⊲",vartriangleright:"⊳",vBar:"⫨",Vbar:"⫫",vBarv:"⫩",Vcy:"В",vcy:"в",vdash:"⊢",vDash:"⊨",Vdash:"⊩",VDash:"⊫",Vdashl:"⫦",veebar:"⊻",vee:"∨",Vee:"⋁",veeeq:"≚",vellip:"⋮",verbar:"|",Verbar:"‖",vert:"|",Vert:"‖",VerticalBar:"∣",VerticalLine:"|",VerticalSeparator:"❘",VerticalTilde:"≀",VeryThinSpace:" ",Vfr:"𝔙",vfr:"𝔳",vltri:"⊲",vnsub:"⊂⃒",vnsup:"⊃⃒",Vopf:"𝕍",vopf:"𝕧",vprop:"∝",vrtri:"⊳",Vscr:"𝒱",vscr:"𝓋",vsubnE:"⫋︀",vsubne:"⊊︀",vsupnE:"⫌︀",vsupne:"⊋︀",Vvdash:"⊪",vzigzag:"⦚",Wcirc:"Ŵ",wcirc:"ŵ",wedbar:"⩟",wedge:"∧",Wedge:"⋀",wedgeq:"≙",weierp:"℘",Wfr:"𝔚",wfr:"𝔴",Wopf:"𝕎",wopf:"𝕨",wp:"℘",wr:"≀",wreath:"≀",Wscr:"𝒲",wscr:"𝓌",xcap:"⋂",xcirc:"◯",xcup:"⋃",xdtri:"▽",Xfr:"𝔛",xfr:"𝔵",xharr:"⟷",xhArr:"⟺",Xi:"Ξ",xi:"ξ",xlarr:"⟵",xlArr:"⟸",xmap:"⟼",xnis:"⋻",xodot:"⨀",Xopf:"𝕏",xopf:"𝕩",xoplus:"⨁",xotime:"⨂",xrarr:"⟶",xrArr:"⟹",Xscr:"𝒳",xscr:"𝓍",xsqcup:"⨆",xuplus:"⨄",xutri:"△",xvee:"⋁",xwedge:"⋀",Yacute:"Ý",yacute:"ý",YAcy:"Я",yacy:"я",Ycirc:"Ŷ",ycirc:"ŷ",Ycy:"Ы",ycy:"ы",yen:"¥",Yfr:"𝔜",yfr:"𝔶",YIcy:"Ї",yicy:"ї",Yopf:"𝕐",yopf:"𝕪",Yscr:"𝒴",yscr:"𝓎",YUcy:"Ю",yucy:"ю",yuml:"ÿ",Yuml:"Ÿ",Zacute:"Ź",zacute:"ź",Zcaron:"Ž",zcaron:"ž",Zcy:"З",zcy:"з",Zdot:"Ż",zdot:"ż",zeetrf:"ℨ",ZeroWidthSpace:"​",Zeta:"Ζ",zeta:"ζ",zfr:"𝔷",Zfr:"ℨ",ZHcy:"Ж",zhcy:"ж",zigrarr:"⇝",zopf:"𝕫",Zopf:"ℤ",Zscr:"𝒵",zscr:"𝓏",zwj:"‍",zwnj:"‌"}},{}],37:[function(t,e,r){e.exports={Aacute:"Á",aacute:"á",Acirc:"Â",acirc:"â",acute:"´",AElig:"Æ",aelig:"æ",Agrave:"À",agrave:"à",amp:"&",AMP:"&",Aring:"Å",aring:"å",Atilde:"Ã",atilde:"ã",Auml:"Ä",auml:"ä",brvbar:"¦",Ccedil:"Ç",ccedil:"ç",cedil:"¸",cent:"¢",copy:"©",COPY:"©",curren:"¤",deg:"°",divide:"÷",Eacute:"É",eacute:"é",Ecirc:"Ê",ecirc:"ê",Egrave:"È",egrave:"è",ETH:"Ð",eth:"ð",Euml:"Ë",euml:"ë",frac12:"½",frac14:"¼",frac34:"¾",gt:">",GT:">",Iacute:"Í",iacute:"í",Icirc:"Î",icirc:"î",iexcl:"¡",Igrave:"Ì",igrave:"ì",iquest:"¿",Iuml:"Ï",iuml:"ï",laquo:"«",lt:"<",LT:"<",macr:"¯",micro:"µ",middot:"·",nbsp:" ",not:"¬",Ntilde:"Ñ",ntilde:"ñ",Oacute:"Ó",oacute:"ó",Ocirc:"Ô",ocirc:"ô",Ograve:"Ò",ograve:"ò",ordf:"ª",ordm:"º",Oslash:"Ø",oslash:"ø",Otilde:"Õ",otilde:"õ",Ouml:"Ö",ouml:"ö",para:"¶",plusmn:"±",pound:"£",quot:'"',QUOT:'"',raquo:"»",reg:"®",REG:"®",sect:"§",shy:"­",sup1:"¹",sup2:"²",sup3:"³",szlig:"ß",THORN:"Þ",thorn:"þ",times:"×",Uacute:"Ú",uacute:"ú",Ucirc:"Û",ucirc:"û",Ugrave:"Ù",ugrave:"ù",uml:"¨",Uuml:"Ü",uuml:"ü",Yacute:"Ý",yacute:"ý",yen:"¥",yuml:"ÿ"}},{}],38:[function(t,e,r){arguments[4][22][0].apply(r,arguments)},{dup:22}],39:[function(t,e,r){var n,i="object"==typeof Reflect?Reflect:null,o=i&&"function"==typeof i.apply?i.apply:function(t,e,r){return Function.prototype.apply.call(t,e,r)};n=i&&"function"==typeof i.ownKeys?i.ownKeys:Object.getOwnPropertySymbols?function(t){return Object.getOwnPropertyNames(t).concat(Object.getOwnPropertySymbols(t))}:function(t){return Object.getOwnPropertyNames(t)};var s=Number.isNaN||function(t){return t!=t};function a(){a.init.call(this)}e.exports=a,e.exports.once=function(t,e){return new Promise((function(r,n){function i(r){t.removeListener(e,o),n(r)}function o(){"function"==typeof t.removeListener&&t.removeListener("error",i),r([].slice.call(arguments))}b(t,e,o,{once:!0}),"error"!==e&&function(t,e,r){"function"==typeof t.on&&b(t,"error",e,r)}(t,i,{once:!0})}))},a.EventEmitter=a,a.prototype._events=void 0,a.prototype._eventsCount=0,a.prototype._maxListeners=void 0;var c=10;function u(t){if("function"!=typeof t)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof t)}function l(t){return void 0===t._maxListeners?a.defaultMaxListeners:t._maxListeners}function p(t,e,r,n){var i,o,s,a;if(u(r),void 0===(o=t._events)?(o=t._events=Object.create(null),t._eventsCount=0):(void 0!==o.newListener&&(t.emit("newListener",e,r.listener?r.listener:r),o=t._events),s=o[e]),void 0===s)s=o[e]=r,++t._eventsCount;else if("function"==typeof s?s=o[e]=n?[r,s]:[s,r]:n?s.unshift(r):s.push(r),(i=l(t))>0&&s.length>i&&!s.warned){s.warned=!0;var c=new Error("Possible EventEmitter memory leak detected. "+s.length+" "+String(e)+" listeners added. Use emitter.setMaxListeners() to increase limit");c.name="MaxListenersExceededWarning",c.emitter=t,c.type=e,c.count=s.length,a=c,console&&console.warn&&console.warn(a)}return t}function h(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function f(t,e,r){var n={fired:!1,wrapFn:void 0,target:t,type:e,listener:r},i=h.bind(n);return i.listener=r,n.wrapFn=i,i}function d(t,e,r){var n=t._events;if(void 0===n)return[];var i=n[e];return void 0===i?[]:"function"==typeof i?r?[i.listener||i]:[i]:r?function(t){for(var e=new Array(t.length),r=0;r0&&(s=e[0]),s instanceof Error)throw s;var a=new Error("Unhandled error."+(s?" ("+s.message+")":""));throw a.context=s,a}var c=i[t];if(void 0===c)return!1;if("function"==typeof c)o(c,this,e);else{var u=c.length,l=m(c,u);for(r=0;r=0;o--)if(r[o]===e||r[o].listener===e){s=r[o].listener,i=o;break}if(i<0)return this;0===i?r.shift():function(t,e){for(;e+1=0;n--)this.removeListener(t,e[n]);return this},a.prototype.listeners=function(t){return d(this,t,!0)},a.prototype.rawListeners=function(t){return d(this,t,!1)},a.listenerCount=function(t,e){return"function"==typeof t.listenerCount?t.listenerCount(e):g.call(t,e)},a.prototype.listenerCount=g,a.prototype.eventNames=function(){return this._eventsCount>0?n(this._events):[]}},{}],40:[function(t,e,r){function n(t){this._cbs=t||{},this.events=[]}e.exports=n;var i=t("./").EVENTS;Object.keys(i).forEach((function(t){if(0===i[t])t="on"+t,n.prototype[t]=function(){this.events.push([t]),this._cbs[t]&&this._cbs[t]()};else if(1===i[t])t="on"+t,n.prototype[t]=function(e){this.events.push([t,e]),this._cbs[t]&&this._cbs[t](e)};else{if(2!==i[t])throw Error("wrong number of arguments");t="on"+t,n.prototype[t]=function(e,r){this.events.push([t,e,r]),this._cbs[t]&&this._cbs[t](e,r)}}})),n.prototype.onreset=function(){this.events=[],this._cbs.onreset&&this._cbs.onreset()},n.prototype.restart=function(){this._cbs.onreset&&this._cbs.onreset();for(var t=0,e=this.events.length;t0;this._cbs.onclosetag(this._stack[--t]));this._cbs.onend&&this._cbs.onend()},l.prototype.reset=function(){this._cbs.onreset&&this._cbs.onreset(),this._tokenizer.reset(),this._tagname="",this._attribname="",this._attribs=null,this._stack=[],this._cbs.onparserinit&&this._cbs.onparserinit(this)},l.prototype.parseComplete=function(t){this.reset(),this.end(t)},l.prototype.write=function(t){this._tokenizer.write(t)},l.prototype.end=function(t){this._tokenizer.end(t)},l.prototype.pause=function(){this._tokenizer.pause()},l.prototype.resume=function(){this._tokenizer.resume()},l.prototype.parseChunk=l.prototype.write,l.prototype.done=l.prototype.end,e.exports=l},{"./Tokenizer.js":45,events:39,inherits:49}],43:[function(t,e,r){function n(t){this._cbs=t||{}}e.exports=n;var i=t("./").EVENTS;Object.keys(i).forEach((function(t){if(0===i[t])t="on"+t,n.prototype[t]=function(){this._cbs[t]&&this._cbs[t]()};else if(1===i[t])t="on"+t,n.prototype[t]=function(e){this._cbs[t]&&this._cbs[t](e)};else{if(2!==i[t])throw Error("wrong number of arguments");t="on"+t,n.prototype[t]=function(e,r){this._cbs[t]&&this._cbs[t](e,r)}}}))},{"./":47}],44:[function(t,e,r){e.exports=i;var n=t("./WritableStream.js");function i(t){n.call(this,new o(this),t)}function o(t){this.scope=t}t("inherits")(i,n),i.prototype.readable=!0;var s=t("../").EVENTS;Object.keys(s).forEach((function(t){if(0===s[t])o.prototype["on"+t]=function(){this.scope.emit(t)};else if(1===s[t])o.prototype["on"+t]=function(e){this.scope.emit(t,e)};else{if(2!==s[t])throw Error("wrong number of arguments!");o.prototype["on"+t]=function(e,r){this.scope.emit(t,e,r)}}}))},{"../":47,"./WritableStream.js":46,inherits:49}],45:[function(t,e,r){e.exports=mt;var n=t("entities/lib/decode_codepoint.js"),i=t("entities/maps/entities.json"),o=t("entities/maps/legacy.json"),s=t("entities/maps/xml.json"),a=0,c=a++,u=a++,l=a++,p=a++,h=a++,f=a++,d=a++,g=a++,m=a++,b=a++,y=a++,_=a++,v=a++,w=a++,x=a++,q=a++,E=a++,S=a++,T=a++,A=a++,L=a++,k=a++,D=a++,C=a++,N=a++,B=a++,R=a++,U=a++,O=a++,I=a++,M=a++,j=a++,P=a++,H=a++,V=a++,G=a++,F=a++,z=a++,$=a++,Y=a++,X=a++,J=a++,W=a++,Z=a++,Q=a++,K=a++,tt=a++,et=a++,rt=a++,nt=a++,it=a++,ot=a++,st=a++,at=a++,ct=a++,ut=0,lt=ut++,pt=ut++,ht=ut++;function ft(t){return" "===t||"\n"===t||"\t"===t||"\f"===t||"\r"===t}function dt(t,e,r){var n=t.toLowerCase();return t===n?function(t){t===n?this._state=e:(this._state=r,this._index--)}:function(i){i===n||i===t?this._state=e:(this._state=r,this._index--)}}function gt(t,e){var r=t.toLowerCase();return function(n){n===r||n===t?this._state=e:(this._state=l,this._index--)}}function mt(t,e){this._state=c,this._buffer="",this._sectionStart=0,this._index=0,this._bufferOffset=0,this._baseState=c,this._special=lt,this._cbs=e,this._running=!0,this._ended=!1,this._xmlMode=!(!t||!t.xmlMode),this._decodeEntities=!(!t||!t.decodeEntities)}mt.prototype._stateText=function(t){"<"===t?(this._index>this._sectionStart&&this._cbs.ontext(this._getSection()),this._state=u,this._sectionStart=this._index):this._decodeEntities&&this._special===lt&&"&"===t&&(this._index>this._sectionStart&&this._cbs.ontext(this._getSection()),this._baseState=c,this._state=it,this._sectionStart=this._index)},mt.prototype._stateBeforeTagName=function(t){"/"===t?this._state=h:"<"===t?(this._cbs.ontext(this._getSection()),this._sectionStart=this._index):">"===t||this._special!==lt||ft(t)?this._state=c:"!"===t?(this._state=x,this._sectionStart=this._index+1):"?"===t?(this._state=E,this._sectionStart=this._index+1):(this._state=this._xmlMode||"s"!==t&&"S"!==t?l:M,this._sectionStart=this._index)},mt.prototype._stateInTagName=function(t){("/"===t||">"===t||ft(t))&&(this._emitToken("onopentagname"),this._state=g,this._index--)},mt.prototype._stateBeforeCloseingTagName=function(t){ft(t)||(">"===t?this._state=c:this._special!==lt?"s"===t||"S"===t?this._state=j:(this._state=c,this._index--):(this._state=f,this._sectionStart=this._index))},mt.prototype._stateInCloseingTagName=function(t){(">"===t||ft(t))&&(this._emitToken("onclosetag"),this._state=d,this._index--)},mt.prototype._stateAfterCloseingTagName=function(t){">"===t&&(this._state=c,this._sectionStart=this._index+1)},mt.prototype._stateBeforeAttributeName=function(t){">"===t?(this._cbs.onopentagend(),this._state=c,this._sectionStart=this._index+1):"/"===t?this._state=p:ft(t)||(this._state=m,this._sectionStart=this._index)},mt.prototype._stateInSelfClosingTag=function(t){">"===t?(this._cbs.onselfclosingtag(),this._state=c,this._sectionStart=this._index+1):ft(t)||(this._state=g,this._index--)},mt.prototype._stateInAttributeName=function(t){("="===t||"/"===t||">"===t||ft(t))&&(this._cbs.onattribname(this._getSection()),this._sectionStart=-1,this._state=b,this._index--)},mt.prototype._stateAfterAttributeName=function(t){"="===t?this._state=y:"/"===t||">"===t?(this._cbs.onattribend(),this._state=g,this._index--):ft(t)||(this._cbs.onattribend(),this._state=m,this._sectionStart=this._index)},mt.prototype._stateBeforeAttributeValue=function(t){'"'===t?(this._state=_,this._sectionStart=this._index+1):"'"===t?(this._state=v,this._sectionStart=this._index+1):ft(t)||(this._state=w,this._sectionStart=this._index,this._index--)},mt.prototype._stateInAttributeValueDoubleQuotes=function(t){'"'===t?(this._emitToken("onattribdata"),this._cbs.onattribend(),this._state=g):this._decodeEntities&&"&"===t&&(this._emitToken("onattribdata"),this._baseState=this._state,this._state=it,this._sectionStart=this._index)},mt.prototype._stateInAttributeValueSingleQuotes=function(t){"'"===t?(this._emitToken("onattribdata"),this._cbs.onattribend(),this._state=g):this._decodeEntities&&"&"===t&&(this._emitToken("onattribdata"),this._baseState=this._state,this._state=it,this._sectionStart=this._index)},mt.prototype._stateInAttributeValueNoQuotes=function(t){ft(t)||">"===t?(this._emitToken("onattribdata"),this._cbs.onattribend(),this._state=g,this._index--):this._decodeEntities&&"&"===t&&(this._emitToken("onattribdata"),this._baseState=this._state,this._state=it,this._sectionStart=this._index)},mt.prototype._stateBeforeDeclaration=function(t){this._state="["===t?k:"-"===t?S:q},mt.prototype._stateInDeclaration=function(t){">"===t&&(this._cbs.ondeclaration(this._getSection()),this._state=c,this._sectionStart=this._index+1)},mt.prototype._stateInProcessingInstruction=function(t){">"===t&&(this._cbs.onprocessinginstruction(this._getSection()),this._state=c,this._sectionStart=this._index+1)},mt.prototype._stateBeforeComment=function(t){"-"===t?(this._state=T,this._sectionStart=this._index+1):this._state=q},mt.prototype._stateInComment=function(t){"-"===t&&(this._state=A)},mt.prototype._stateAfterComment1=function(t){this._state="-"===t?L:T},mt.prototype._stateAfterComment2=function(t){">"===t?(this._cbs.oncomment(this._buffer.substring(this._sectionStart,this._index-2)),this._state=c,this._sectionStart=this._index+1):"-"!==t&&(this._state=T)},mt.prototype._stateBeforeCdata1=dt("C",D,q),mt.prototype._stateBeforeCdata2=dt("D",C,q),mt.prototype._stateBeforeCdata3=dt("A",N,q),mt.prototype._stateBeforeCdata4=dt("T",B,q),mt.prototype._stateBeforeCdata5=dt("A",R,q),mt.prototype._stateBeforeCdata6=function(t){"["===t?(this._state=U,this._sectionStart=this._index+1):(this._state=q,this._index--)},mt.prototype._stateInCdata=function(t){"]"===t&&(this._state=O)},mt.prototype._stateAfterCdata1=function(t){this._state="]"===t?I:U},mt.prototype._stateAfterCdata2=function(t){">"===t?(this._cbs.oncdata(this._buffer.substring(this._sectionStart,this._index-2)),this._state=c,this._sectionStart=this._index+1):"]"!==t&&(this._state=U)},mt.prototype._stateBeforeSpecial=function(t){"c"===t||"C"===t?this._state=P:"t"===t||"T"===t?this._state=W:(this._state=l,this._index--)},mt.prototype._stateBeforeSpecialEnd=function(t){this._special!==pt||"c"!==t&&"C"!==t?this._special!==ht||"t"!==t&&"T"!==t?this._state=c:this._state=tt:this._state=z},mt.prototype._stateBeforeScript1=gt("R",H),mt.prototype._stateBeforeScript2=gt("I",V),mt.prototype._stateBeforeScript3=gt("P",G),mt.prototype._stateBeforeScript4=gt("T",F),mt.prototype._stateBeforeScript5=function(t){("/"===t||">"===t||ft(t))&&(this._special=pt),this._state=l,this._index--},mt.prototype._stateAfterScript1=dt("R",$,c),mt.prototype._stateAfterScript2=dt("I",Y,c),mt.prototype._stateAfterScript3=dt("P",X,c),mt.prototype._stateAfterScript4=dt("T",J,c),mt.prototype._stateAfterScript5=function(t){">"===t||ft(t)?(this._special=lt,this._state=f,this._sectionStart=this._index-6,this._index--):this._state=c},mt.prototype._stateBeforeStyle1=gt("Y",Z),mt.prototype._stateBeforeStyle2=gt("L",Q),mt.prototype._stateBeforeStyle3=gt("E",K),mt.prototype._stateBeforeStyle4=function(t){("/"===t||">"===t||ft(t))&&(this._special=ht),this._state=l,this._index--},mt.prototype._stateAfterStyle1=dt("Y",et,c),mt.prototype._stateAfterStyle2=dt("L",rt,c),mt.prototype._stateAfterStyle3=dt("E",nt,c),mt.prototype._stateAfterStyle4=function(t){">"===t||ft(t)?(this._special=lt,this._state=f,this._sectionStart=this._index-5,this._index--):this._state=c},mt.prototype._stateBeforeEntity=dt("#",ot,st),mt.prototype._stateBeforeNumericEntity=dt("X",ct,at),mt.prototype._parseNamedEntityStrict=function(){if(this._sectionStart+16&&(e=6);e>=2;){var r=this._buffer.substr(t,e);if(o.hasOwnProperty(r))return this._emitPartial(o[r]),void(this._sectionStart+=e+1);e--}},mt.prototype._stateInNamedEntity=function(t){";"===t?(this._parseNamedEntityStrict(),this._sectionStart+1"z")&&(t<"A"||t>"Z")&&(t<"0"||t>"9")&&(this._xmlMode||this._sectionStart+1===this._index||(this._baseState!==c?"="!==t&&this._parseNamedEntityStrict():this._parseLegacyEntity()),this._state=this._baseState,this._index--)},mt.prototype._decodeNumericEntity=function(t,e){var r=this._sectionStart+t;if(r!==this._index){var i=this._buffer.substring(r,this._index),o=parseInt(i,e);this._emitPartial(n(o)),this._sectionStart=this._index}else this._sectionStart--;this._state=this._baseState},mt.prototype._stateInNumericEntity=function(t){";"===t?(this._decodeNumericEntity(2,10),this._sectionStart++):(t<"0"||t>"9")&&(this._xmlMode?this._state=this._baseState:this._decodeNumericEntity(2,10),this._index--)},mt.prototype._stateInHexEntity=function(t){";"===t?(this._decodeNumericEntity(3,16),this._sectionStart++):(t<"a"||t>"f")&&(t<"A"||t>"F")&&(t<"0"||t>"9")&&(this._xmlMode?this._state=this._baseState:this._decodeNumericEntity(3,16),this._index--)},mt.prototype._cleanup=function(){this._sectionStart<0?(this._buffer="",this._bufferOffset+=this._index,this._index=0):this._running&&(this._state===c?(this._sectionStart!==this._index&&this._cbs.ontext(this._buffer.substr(this._sectionStart)),this._buffer="",this._bufferOffset+=this._index,this._index=0):this._sectionStart===this._index?(this._buffer="",this._bufferOffset+=this._index,this._index=0):(this._buffer=this._buffer.substr(this._sectionStart),this._index-=this._sectionStart,this._bufferOffset+=this._sectionStart),this._sectionStart=0)},mt.prototype.write=function(t){this._ended&&this._cbs.onerror(Error(".write() after done!")),this._buffer+=t,this._parse()},mt.prototype._parse=function(){for(;this._index */ -r.read=function(t,e,r,n,i){var o,s,a=8*i-n-1,c=(1<>1,l=-7,p=r?i-1:0,h=r?-1:1,f=t[e+p];for(p+=h,o=f&(1<<-l)-1,f>>=-l,l+=a;l>0;o=256*o+t[e+p],p+=h,l-=8);for(s=o&(1<<-l)-1,o>>=-l,l+=n;l>0;s=256*s+t[e+p],p+=h,l-=8);if(0===o)o=1-u;else{if(o===c)return s?NaN:1/0*(f?-1:1);s+=Math.pow(2,n),o-=u}return(f?-1:1)*s*Math.pow(2,o-n)},r.write=function(t,e,r,n,i,o){var s,a,c,u=8*o-i-1,l=(1<>1,h=23===i?Math.pow(2,-24)-Math.pow(2,-77):0,f=n?0:o-1,d=n?1:-1,g=e<0||0===e&&1/e<0?1:0;for(e=Math.abs(e),isNaN(e)||e===1/0?(a=isNaN(e)?1:0,s=l):(s=Math.floor(Math.log(e)/Math.LN2),e*(c=Math.pow(2,-s))<1&&(s--,c*=2),(e+=s+p>=1?h/c:h*Math.pow(2,1-p))*c>=2&&(s++,c/=2),s+p>=l?(a=0,s=l):s+p>=1?(a=(e*c-1)*Math.pow(2,i),s+=p):(a=e*Math.pow(2,p-1)*Math.pow(2,i),s=0));i>=8;t[r+f]=255&a,f+=d,a/=256,i-=8);for(s=s<0;t[r+f]=255&s,f+=d,s/=256,u-=8);t[r+f-d]|=128*g}},{}],49:[function(t,e,r){"function"==typeof Object.create?e.exports=function(t,e){e&&(t.super_=e,t.prototype=Object.create(e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}))}:e.exports=function(t,e){if(e){t.super_=e;var r=function(){};r.prototype=e.prototype,t.prototype=new r,t.prototype.constructor=t}}},{}]},{},[1]); diff --git a/web/js/turndown-plugin-gfm.js b/web/js/turndown-plugin-gfm.js new file mode 100644 index 0000000..4d468d8 --- /dev/null +++ b/web/js/turndown-plugin-gfm.js @@ -0,0 +1,166 @@ +/*! turndown-plugin-gfm | github.com/mixmark-io/turndown-plugin-gfm */ +var turndownPluginGfm = (function (exports) { +'use strict'; + +var highlightRegExp = /highlight-(?:text|source)-([a-z0-9]+)/; + +function highlightedCodeBlock (turndownService) { + turndownService.addRule('highlightedCodeBlock', { + filter: function (node) { + var firstChild = node.firstChild; + return ( + node.nodeName === 'DIV' && + highlightRegExp.test(node.className) && + firstChild && + firstChild.nodeName === 'PRE' + ) + }, + replacement: function (content, node, options) { + var className = node.className || ''; + var language = (className.match(highlightRegExp) || [null, ''])[1]; + + return ( + '\n\n' + options.fence + language + '\n' + + node.firstChild.textContent + + '\n' + options.fence + '\n\n' + ) + } + }); +} + +function strikethrough (turndownService) { + turndownService.addRule('strikethrough', { + filter: ['del', 's', 'strike'], + replacement: function (content) { + return '~' + content + '~' + } + }); +} + +var indexOf = Array.prototype.indexOf; +var every = Array.prototype.every; +var rules = {}; + +rules.tableCell = { + filter: ['th', 'td'], + replacement: function (content, node) { + return cell(content, node) + } +}; + +rules.tableRow = { + filter: 'tr', + replacement: function (content, node) { + var borderCells = ''; + var alignMap = { left: ':--', right: '--:', center: ':-:' }; + + if (isHeadingRow(node)) { + for (var i = 0; i < node.childNodes.length; i++) { + var border = '---'; + var align = ( + node.childNodes[i].getAttribute('align') || '' + ).toLowerCase(); + + if (align) border = alignMap[align] || border; + + borderCells += cell(border, node.childNodes[i]); + } + } + return '\n' + content + (borderCells ? '\n' + borderCells : '') + } +}; + +rules.table = { + // Only convert tables with a heading row. + // Tables with no heading row are kept using `keep` (see below). + filter: function (node) { + return node.nodeName === 'TABLE' && isHeadingRow(node.rows[0]) + }, + + replacement: function (content) { + // Ensure there are no blank lines + content = content.replace('\n\n', '\n'); + return '\n\n' + content + '\n\n' + } +}; + +rules.tableSection = { + filter: ['thead', 'tbody', 'tfoot'], + replacement: function (content) { + return content + } +}; + +// A tr is a heading row if: +// - the parent is a THEAD +// - or if its the first child of the TABLE or the first TBODY (possibly +// following a blank THEAD) +// - and every cell is a TH +function isHeadingRow (tr) { + var parentNode = tr.parentNode; + return ( + parentNode.nodeName === 'THEAD' || + ( + parentNode.firstChild === tr && + (parentNode.nodeName === 'TABLE' || isFirstTbody(parentNode)) && + every.call(tr.childNodes, function (n) { return n.nodeName === 'TH' }) + ) + ) +} + +function isFirstTbody (element) { + var previousSibling = element.previousSibling; + return ( + element.nodeName === 'TBODY' && ( + !previousSibling || + ( + previousSibling.nodeName === 'THEAD' && + /^\s*$/i.test(previousSibling.textContent) + ) + ) + ) +} + +function cell (content, node) { + var index = indexOf.call(node.parentNode.childNodes, node); + var prefix = ' '; + if (index === 0) prefix = '| '; + return prefix + content + ' |' +} + +function tables (turndownService) { + turndownService.keep(function (node) { + return node.nodeName === 'TABLE' && !isHeadingRow(node.rows[0]) + }); + for (var key in rules) turndownService.addRule(key, rules[key]); +} + +function taskListItems (turndownService) { + turndownService.addRule('taskListItems', { + filter: function (node) { + return node.type === 'checkbox' && node.parentNode.nodeName === 'LI' + }, + replacement: function (content, node) { + return (node.checked ? '[x]' : '[ ]') + ' ' + } + }); +} + +function gfm (turndownService) { + turndownService.use([ + highlightedCodeBlock, + strikethrough, + tables, + taskListItems + ]); +} + +exports.gfm = gfm; +exports.highlightedCodeBlock = highlightedCodeBlock; +exports.strikethrough = strikethrough; +exports.tables = tables; +exports.taskListItems = taskListItems; + +return exports; + +}({})); diff --git a/web/js/turndown.js b/web/js/turndown.js new file mode 100644 index 0000000..d4ace5f --- /dev/null +++ b/web/js/turndown.js @@ -0,0 +1,974 @@ +/*! Turndown v7.1.1 | github.com/mixmark-io/turndown | Modified by S2OJ ( https://github.com/laurent22/joplin-turndown/commit/456d585db54f6d667970b9514bd697f57b92301c.diff ) */ +var TurndownService = (function () { + 'use strict'; + + function extend (destination) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) { + if (source.hasOwnProperty(key)) destination[key] = source[key]; + } + } + return destination + } + + function repeat (character, count) { + return Array(count + 1).join(character) + } + + function trimLeadingNewlines (string) { + return string.replace(/^\n*/, '') + } + + function trimTrailingNewlines (string) { + // avoid match-at-end regexp bottleneck, see #370 + var indexEnd = string.length; + while (indexEnd > 0 && string[indexEnd - 1] === '\n') indexEnd--; + return string.substring(0, indexEnd) + } + + var blockElements = [ + 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS', + 'CENTER', 'DD', 'DIR', 'DIV', 'DL', 'DT', 'FIELDSET', 'FIGCAPTION', 'FIGURE', + 'FOOTER', 'FORM', 'FRAMESET', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER', + 'HGROUP', 'HR', 'HTML', 'ISINDEX', 'LI', 'MAIN', 'MENU', 'NAV', 'NOFRAMES', + 'NOSCRIPT', 'OL', 'OUTPUT', 'P', 'PRE', 'SECTION', 'TABLE', 'TBODY', 'TD', + 'TFOOT', 'TH', 'THEAD', 'TR', 'UL' + ]; + + function isBlock (node) { + return is(node, blockElements) + } + + var voidElements = [ + 'AREA', 'BASE', 'BR', 'COL', 'COMMAND', 'EMBED', 'HR', 'IMG', 'INPUT', + 'KEYGEN', 'LINK', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR' + ]; + + function isVoid (node) { + return is(node, voidElements) + } + + function hasVoid (node) { + return has(node, voidElements) + } + + var meaningfulWhenBlankElements = [ + 'A', 'TABLE', 'THEAD', 'TBODY', 'TFOOT', 'TH', 'TD', 'IFRAME', 'SCRIPT', + 'AUDIO', 'VIDEO' + ]; + + function isMeaningfulWhenBlank (node) { + return is(node, meaningfulWhenBlankElements) + } + + function hasMeaningfulWhenBlank (node) { + return has(node, meaningfulWhenBlankElements) + } + + function is (node, tagNames) { + return tagNames.indexOf(node.nodeName) >= 0 + } + + function has (node, tagNames) { + return ( + node.getElementsByTagName && + tagNames.some(function (tagName) { + return node.getElementsByTagName(tagName).length + }) + ) + } + + var rules = {}; + + rules.paragraph = { + filter: 'p', + + replacement: function (content) { + return '\n\n' + content + '\n\n' + } + }; + + rules.lineBreak = { + filter: 'br', + + replacement: function (content, node, options) { + return options.br + '\n' + } + }; + + rules.heading = { + filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'], + + replacement: function (content, node, options) { + var hLevel = Number(node.nodeName.charAt(1)); + + if (options.headingStyle === 'setext' && hLevel < 3) { + var underline = repeat((hLevel === 1 ? '=' : '-'), content.length); + return ( + '\n\n' + content + '\n' + underline + '\n\n' + ) + } else { + return '\n\n' + repeat('#', hLevel) + ' ' + content + '\n\n' + } + } + }; + + rules.blockquote = { + filter: 'blockquote', + + replacement: function (content) { + content = content.replace(/^\n+|\n+$/g, ''); + content = content.replace(/^/gm, '> '); + return '\n\n' + content + '\n\n' + } + }; + + rules.list = { + filter: ['ul', 'ol'], + + replacement: function (content, node) { + var parent = node.parentNode; + if (parent.nodeName === 'LI' && parent.lastElementChild === node) { + return '\n' + content + } else { + return '\n\n' + content + '\n\n' + } + } + }; + + rules.listItem = { + filter: 'li', + + replacement: function (content, node, options) { + content = content + .replace(/^\n+/, '') // remove leading newlines + .replace(/\n+$/, '\n') // replace trailing newlines with just a single one + .replace(/\n/gm, '\n '); // indent + var prefix = options.bulletListMarker + ' '; + var parent = node.parentNode; + if (parent.nodeName === 'OL') { + var start = parent.getAttribute('start'); + var index = Array.prototype.indexOf.call(parent.children, node); + prefix = (start ? Number(start) + index : index + 1) + '. '; + } + return ( + prefix + content + (node.nextSibling && !/\n$/.test(content) ? '\n' : '') + ) + } + }; + + rules.indentedCodeBlock = { + filter: function (node, options) { + return ( + options.codeBlockStyle === 'indented' && + node.nodeName === 'PRE' && + node.firstChild && + node.firstChild.nodeName === 'CODE' + ) + }, + + replacement: function (content, node, options) { + return ( + '\n\n ' + + node.firstChild.textContent.replace(/\n/g, '\n ') + + '\n\n' + ) + } + }; + + rules.fencedCodeBlock = { + filter: function (node, options) { + return ( + options.codeBlockStyle === 'fenced' && + node.nodeName === 'PRE' && + node.firstChild && + node.firstChild.nodeName === 'CODE' + ) + }, + + replacement: function (content, node, options) { + var className = node.firstChild.getAttribute('class') || ''; + var language = (className.match(/language-(\S+)/) || [null, ''])[1]; + var code = node.firstChild.textContent; + + var fenceChar = options.fence.charAt(0); + var fenceSize = 3; + var fenceInCodeRegex = new RegExp('^' + fenceChar + '{3,}', 'gm'); + + var match; + while ((match = fenceInCodeRegex.exec(code))) { + if (match[0].length >= fenceSize) { + fenceSize = match[0].length + 1; + } + } + + var fence = repeat(fenceChar, fenceSize); + + return ( + '\n\n' + fence + language + '\n' + + code.replace(/\n$/, '') + + '\n' + fence + '\n\n' + ) + } + }; + + rules.horizontalRule = { + filter: 'hr', + + replacement: function (content, node, options) { + return '\n\n' + options.hr + '\n\n' + } + }; + + rules.inlineLink = { + filter: function (node, options) { + return ( + options.linkStyle === 'inlined' && + node.nodeName === 'A' && + node.getAttribute('href') + ) + }, + + replacement: function (content, node) { + var href = node.getAttribute('href'); + var title = cleanAttribute(node.getAttribute('title')); + if (title) title = ' "' + title + '"'; + return '[' + content + '](' + href + title + ')' + } + }; + + rules.referenceLink = { + filter: function (node, options) { + return ( + options.linkStyle === 'referenced' && + node.nodeName === 'A' && + node.getAttribute('href') + ) + }, + + replacement: function (content, node, options) { + var href = node.getAttribute('href'); + var title = cleanAttribute(node.getAttribute('title')); + if (title) title = ' "' + title + '"'; + var replacement; + var reference; + + switch (options.linkReferenceStyle) { + case 'collapsed': + replacement = '[' + content + '][]'; + reference = '[' + content + ']: ' + href + title; + break + case 'shortcut': + replacement = '[' + content + ']'; + reference = '[' + content + ']: ' + href + title; + break + default: + var id = this.references.length + 1; + replacement = '[' + content + '][' + id + ']'; + reference = '[' + id + ']: ' + href + title; + } + + this.references.push(reference); + return replacement + }, + + references: [], + + append: function (options) { + var references = ''; + if (this.references.length) { + references = '\n\n' + this.references.join('\n') + '\n\n'; + this.references = []; // Reset references + } + return references + } + }; + + rules.emphasis = { + filter: ['em', 'i'], + + replacement: function (content, node, options) { + if (!content.trim()) return '' + return options.emDelimiter + content + options.emDelimiter + } + }; + + rules.strong = { + filter: ['strong', 'b'], + + replacement: function (content, node, options) { + if (!content.trim()) return '' + return options.strongDelimiter + content + options.strongDelimiter + } + }; + + rules.code = { + filter: function (node) { + var hasSiblings = node.previousSibling || node.nextSibling; + var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings; + + return node.nodeName === 'CODE' && !isCodeBlock + }, + + replacement: function (content) { + if (!content) return '' + content = content.replace(/\r?\n|\r/g, ' '); + + var extraSpace = /^`|^ .*?[^ ].* $|`$/.test(content) ? ' ' : ''; + var delimiter = '`'; + var matches = content.match(/`+/gm) || []; + while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; + + return delimiter + extraSpace + content + extraSpace + delimiter + } + }; + + rules.image = { + filter: 'img', + + replacement: function (content, node) { + var alt = cleanAttribute(node.getAttribute('alt')); + var src = node.getAttribute('src') || ''; + var title = cleanAttribute(node.getAttribute('title')); + var titlePart = title ? ' "' + title + '"' : ''; + return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : '' + } + }; + + function cleanAttribute (attribute) { + return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : '' + } + + /** + * Manages a collection of rules used to convert HTML to Markdown + */ + + function Rules (options) { + this.options = options; + this._keep = []; + this._remove = []; + + this.blankRule = { + replacement: options.blankReplacement + }; + + this.keepReplacement = options.keepReplacement; + + this.defaultRule = { + replacement: options.defaultReplacement + }; + + this.array = []; + for (var key in options.rules) this.array.push(options.rules[key]); + } + + Rules.prototype = { + add: function (key, rule) { + this.array.unshift(rule); + }, + + keep: function (filter) { + this._keep.unshift({ + filter: filter, + replacement: this.keepReplacement + }); + }, + + remove: function (filter) { + this._remove.unshift({ + filter: filter, + replacement: function () { + return '' + } + }); + }, + + forNode: function (node) { + if (node.isBlank) return this.blankRule + var rule; + + if ((rule = findRule(this.array, node, this.options))) return rule + if ((rule = findRule(this._keep, node, this.options))) return rule + if ((rule = findRule(this._remove, node, this.options))) return rule + + return this.defaultRule + }, + + forEach: function (fn) { + for (var i = 0; i < this.array.length; i++) fn(this.array[i], i); + } + }; + + function findRule (rules, node, options) { + for (var i = 0; i < rules.length; i++) { + var rule = rules[i]; + if (filterValue(rule, node, options)) return rule + } + return void 0 + } + + function filterValue (rule, node, options) { + var filter = rule.filter; + if (typeof filter === 'string') { + if (filter === node.nodeName.toLowerCase()) return true + } else if (Array.isArray(filter)) { + if (filter.indexOf(node.nodeName.toLowerCase()) > -1) return true + } else if (typeof filter === 'function') { + if (filter.call(rule, node, options)) return true + } else { + throw new TypeError('`filter` needs to be a string, array, or function') + } + } + + /** + * The collapseWhitespace function is adapted from collapse-whitespace + * by Luc Thevenard. + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Luc Thevenard + * + * 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. + */ + + /** + * collapseWhitespace(options) removes extraneous whitespace from an the given element. + * + * @param {Object} options + */ + function collapseWhitespace (options) { + var element = options.element; + var isBlock = options.isBlock; + var isVoid = options.isVoid; + var isPre = options.isPre || function (node) { + return node.nodeName === 'PRE' + }; + + if (!element.firstChild || isPre(element)) return + + var prevText = null; + var keepLeadingWs = false; + + var prev = null; + var node = next(prev, element, isPre); + + while (node !== element) { + if (node.nodeType === 3 || node.nodeType === 4) { // Node.TEXT_NODE or Node.CDATA_SECTION_NODE + var text = node.data.replace(/[ \r\n\t]+/g, ' '); + + if ((!prevText || / $/.test(prevText.data)) && + !keepLeadingWs && text[0] === ' ') { + text = text.substr(1); + } + + // `text` might be empty at this point. + if (!text) { + node = remove(node); + continue + } + + node.data = text; + + prevText = node; + } else if (node.nodeType === 1) { // Node.ELEMENT_NODE + if (isBlock(node) || node.nodeName === 'BR') { + if (prevText) { + prevText.data = prevText.data.replace(/ $/, ''); + } + + prevText = null; + keepLeadingWs = false; + } else if (isVoid(node) || isPre(node)) { + // Avoid trimming space around non-block, non-BR void elements and inline PRE. + prevText = null; + keepLeadingWs = true; + } else if (prevText) { + // Drop protection if set previously. + keepLeadingWs = false; + } + } else { + node = remove(node); + continue + } + + var nextNode = next(prev, node, isPre); + prev = node; + node = nextNode; + } + + if (prevText) { + prevText.data = prevText.data.replace(/ $/, ''); + if (!prevText.data) { + remove(prevText); + } + } + } + + /** + * remove(node) removes the given node from the DOM and returns the + * next node in the sequence. + * + * @param {Node} node + * @return {Node} node + */ + function remove (node) { + var next = node.nextSibling || node.parentNode; + + node.parentNode.removeChild(node); + + return next + } + + /** + * next(prev, current, isPre) returns the next node in the sequence, given the + * current and previous nodes. + * + * @param {Node} prev + * @param {Node} current + * @param {Function} isPre + * @return {Node} + */ + function next (prev, current, isPre) { + if ((prev && prev.parentNode === current) || isPre(current)) { + return current.nextSibling || current.parentNode + } + + return current.firstChild || current.nextSibling || current.parentNode + } + + /* + * Set up window for Node.js + */ + + var root = (typeof window !== 'undefined' ? window : {}); + + /* + * Parsing HTML strings + */ + + function canParseHTMLNatively () { + var Parser = root.DOMParser; + var canParse = false; + + // Adapted from https://gist.github.com/1129031 + // Firefox/Opera/IE throw errors on unsupported types + try { + // WebKit returns null on unsupported types + if (new Parser().parseFromString('', 'text/html')) { + canParse = true; + } + } catch (e) {} + + return canParse + } + + function createHTMLParser () { + var Parser = function () {}; + + { + if (shouldUseActiveX()) { + Parser.prototype.parseFromString = function (string) { + var doc = new window.ActiveXObject('htmlfile'); + doc.designMode = 'on'; // disable on-page scripts + doc.open(); + doc.write(string); + doc.close(); + return doc + }; + } else { + Parser.prototype.parseFromString = function (string) { + var doc = document.implementation.createHTMLDocument(''); + doc.open(); + doc.write(string); + doc.close(); + return doc + }; + } + } + return Parser + } + + function shouldUseActiveX () { + var useActiveX = false; + try { + document.implementation.createHTMLDocument('').open(); + } catch (e) { + if (window.ActiveXObject) useActiveX = true; + } + return useActiveX + } + + var HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser(); + + function RootNode (input, options) { + var root; + if (typeof input === 'string') { + var doc = htmlParser().parseFromString( + // DOM parsers arrange elements in the and . + // Wrapping in a custom element ensures elements are reliably arranged in + // a single element. + '' + input + '', + 'text/html' + ); + root = doc.getElementById('turndown-root'); + } else { + root = input.cloneNode(true); + } + collapseWhitespace({ + element: root, + isBlock: isBlock, + isVoid: isVoid, + isPre: options.preformattedCode ? isPreOrCode : null + }); + + return root + } + + var _htmlParser; + function htmlParser () { + _htmlParser = _htmlParser || new HTMLParser(); + return _htmlParser + } + + function isPreOrCode (node) { + return node.nodeName === 'PRE' || node.nodeName === 'CODE' + } + + function Node (node, options) { + node.isBlock = isBlock(node); + node.isCode = node.nodeName === 'CODE' || node.parentNode.isCode; + node.isBlank = isBlank(node); + node.flankingWhitespace = flankingWhitespace(node, options); + return node + } + + function isBlank (node) { + return ( + !isVoid(node) && + !isMeaningfulWhenBlank(node) && + /^\s*$/i.test(node.textContent) && + !hasVoid(node) && + !hasMeaningfulWhenBlank(node) + ) + } + + function flankingWhitespace (node, options) { + if (node.isBlock || (options.preformattedCode && node.isCode)) { + return { leading: '', trailing: '' } + } + + var edges = edgeWhitespace(node.textContent); + + // abandon leading ASCII WS if left-flanked by ASCII WS + if (edges.leadingAscii && isFlankedByWhitespace('left', node, options)) { + edges.leading = edges.leadingNonAscii; + } + + // abandon trailing ASCII WS if right-flanked by ASCII WS + if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) { + edges.trailing = edges.trailingNonAscii; + } + + return { leading: edges.leading, trailing: edges.trailing } + } + + function edgeWhitespace (string) { + var m = string.match(/^(([ \t\r\n]*)(\s*))[\s\S]*?((\s*?)([ \t\r\n]*))$/); + return { + leading: m[1], // whole string for whitespace-only strings + leadingAscii: m[2], + leadingNonAscii: m[3], + trailing: m[4], // empty for whitespace-only strings + trailingNonAscii: m[5], + trailingAscii: m[6] + } + } + + function isFlankedByWhitespace (side, node, options) { + var sibling; + var regExp; + var isFlanked; + + if (side === 'left') { + sibling = node.previousSibling; + regExp = / $/; + } else { + sibling = node.nextSibling; + regExp = /^ /; + } + + if (sibling) { + if (sibling.nodeType === 3) { + isFlanked = regExp.test(sibling.nodeValue); + } else if (options.preformattedCode && sibling.nodeName === 'CODE') { + isFlanked = false; + } else if (sibling.nodeType === 1 && !isBlock(sibling)) { + isFlanked = regExp.test(sibling.textContent); + } + } + return isFlanked + } + + var reduce = Array.prototype.reduce; + var escapes = [ + [/\\/g, '\\\\'], + [/\*/g, '\\*'], + [/^-/g, '\\-'], + [/^\+ /g, '\\+ '], + [/^(=+)/g, '\\$1'], + [/^(#{1,6}) /g, '\\$1 '], + [/`/g, '\\`'], + [/^~~~/g, '\\~~~'], + [/\[/g, '\\['], + [/\]/g, '\\]'], + [/^>/g, '\\>'], + [/_/g, '\\_'], + [/^(\d+)\. /g, '$1\\. '] + ]; + + function TurndownService (options) { + if (!(this instanceof TurndownService)) return new TurndownService(options) + + var defaults = { + rules: rules, + headingStyle: 'setext', + hr: '* * *', + bulletListMarker: '*', + codeBlockStyle: 'indented', + fence: '```', + emDelimiter: '_', + strongDelimiter: '**', + linkStyle: 'inlined', + linkReferenceStyle: 'full', + br: ' ', + preformattedCode: false, + blankReplacement: function (content, node) { + return node.isBlock ? '\n\n' : '' + }, + keepReplacement: function (content, node) { + return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML + }, + defaultReplacement: function (content, node) { + return node.isBlock ? '\n\n' + content + '\n\n' : content + } + }; + this.options = extend({}, defaults, options); + this.rules = new Rules(this.options); + } + + TurndownService.prototype = { + /** + * The entry point for converting a string or DOM node to Markdown + * @public + * @param {String|HTMLElement} input The string or DOM node to convert + * @returns A Markdown representation of the input + * @type String + */ + + turndown: function (input) { + if (!canConvert(input)) { + throw new TypeError( + input + ' is not a string, or an element/document/fragment node.' + ) + } + + if (input === '') return '' + + var output = process.call(this, new RootNode(input, this.options)); + return postProcess.call(this, output) + }, + + /** + * Add one or more plugins + * @public + * @param {Function|Array} plugin The plugin or array of plugins to add + * @returns The Turndown instance for chaining + * @type Object + */ + + use: function (plugin) { + if (Array.isArray(plugin)) { + for (var i = 0; i < plugin.length; i++) this.use(plugin[i]); + } else if (typeof plugin === 'function') { + plugin(this); + } else { + throw new TypeError('plugin must be a Function or an Array of Functions') + } + return this + }, + + /** + * Adds a rule + * @public + * @param {String} key The unique key of the rule + * @param {Object} rule The rule + * @returns The Turndown instance for chaining + * @type Object + */ + + addRule: function (key, rule) { + this.rules.add(key, rule); + return this + }, + + /** + * Keep a node (as HTML) that matches the filter + * @public + * @param {String|Array|Function} filter The unique key of the rule + * @returns The Turndown instance for chaining + * @type Object + */ + + keep: function (filter) { + this.rules.keep(filter); + return this + }, + + /** + * Remove a node that matches the filter + * @public + * @param {String|Array|Function} filter The unique key of the rule + * @returns The Turndown instance for chaining + * @type Object + */ + + remove: function (filter) { + this.rules.remove(filter); + return this + }, + + /** + * Escapes Markdown syntax + * @public + * @param {String} string The string to escape + * @returns A string with Markdown syntax escaped + * @type String + */ + + escape: function (string) { + return escapes.reduce(function (accumulator, escape) { + return accumulator.replace(escape[0], escape[1]) + }, string) + } + }; + + /** + * Reduces a DOM node down to its Markdown string equivalent + * @private + * @param {HTMLElement} parentNode The node to convert + * @returns A Markdown representation of the node + * @type String + */ + + function process (parentNode, escapeContent = 'auto') { + var self = this; + return reduce.call(parentNode.childNodes, function (output, node) { + node = new Node(node, self.options); + + var replacement = ''; + if (node.nodeType === 3) { + replacement = node.isCode || escapeContent === false ? node.nodeValue : self.escape(node.nodeValue); + } else if (node.nodeType === 1) { + replacement = replacementForNode.call(self, node); + } + + return join(output, replacement) + }, '') + } + + /** + * Appends strings as each rule requires and trims the output + * @private + * @param {String} output The conversion output + * @returns A trimmed version of the ouput + * @type String + */ + + function postProcess (output) { + var self = this; + this.rules.forEach(function (rule) { + if (typeof rule.append === 'function') { + output = join(output, rule.append(self.options)); + } + }); + + return output.replace(/^[\t\r\n]+/, '').replace(/[\t\r\n\s]+$/, '') + } + + /** + * Converts an element node to its Markdown equivalent + * @private + * @param {HTMLElement} node The node to convert + * @returns A Markdown representation of the node + * @type String + */ + + function replacementForNode (node) { + var rule = this.rules.forNode(node); + var content = process.call(this, node, rule.escapeContent ? rule.escapeContent() : 'auto'); + var whitespace = node.flankingWhitespace; + if (whitespace.leading || whitespace.trailing) content = content.trim(); + return ( + whitespace.leading + + rule.replacement(content, node, this.options) + + whitespace.trailing + ) + } + + /** + * Joins replacement to the current output with appropriate number of new lines + * @private + * @param {String} output The current conversion output + * @param {String} replacement The string to append to the output + * @returns Joined output + * @type String + */ + + function join (output, replacement) { + var s1 = trimTrailingNewlines(output); + var s2 = trimLeadingNewlines(replacement); + var nls = Math.max(output.length - s1.length, replacement.length - s2.length); + var separator = '\n\n'.substring(0, nls); + + return s1 + separator + s2 + } + + /** + * Determines whether an input can be converted + * @private + * @param {String|HTMLElement} input Describe this parameter + * @returns Describe what it returns + * @type String|Object|Array|Boolean|Number + */ + + function canConvert (input) { + return ( + input != null && ( + typeof input === 'string' || + (input.nodeType && ( + input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11 + )) + ) + ) + } + + return TurndownService; + +}()); From 8b2de39c5f03a791b004da5ba6a5a112ba614957 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Wed, 11 Jan 2023 10:48:20 +0800 Subject: [PATCH 09/30] feat: add copy button --- web/app/controllers/submission.php | 22 +++++----- web/app/views/page-footer.php | 5 --- web/app/views/page-header.php | 3 ++ ...oard-polyfill.overwrite-globals.es5.min.js | 2 + web/js/uoj.js | 41 +++++++++++++++++++ 5 files changed, 58 insertions(+), 15 deletions(-) create mode 100644 web/js/clipboard-polyfill.overwrite-globals.es5.min.js diff --git a/web/app/controllers/submission.php b/web/app/controllers/submission.php index 7385144..5f6dcdd 100644 --- a/web/app/controllers/submission.php +++ b/web/app/controllers/submission.php @@ -168,7 +168,9 @@ if ($perm['manager_view']) { ?> - echoContent() ?> +
    + echoContent() ?> +

    @@ -221,17 +223,17 @@ if (UOJSubmission::cur()->hasJudged()) { ?>

    - - printHTML() ?> - + + printHTML() ?> + - - printHTML() ?> - + + printHTML() ?> + - - printHTML() ?> - + + printHTML() ?> +
    diff --git a/web/app/views/page-footer.php b/web/app/views/page-footer.php index 35a9a77..5d806ce 100644 --- a/web/app/views/page-footer.php +++ b/web/app/views/page-footer.php @@ -4,11 +4,6 @@ if (!isset($ShowPageFooter)) { } ?> - + +
    + $tags) : ?> + + +
    + +
    + + + +
    + + + +
    题目难度 @@ -183,7 +262,6 @@ $difficulty_form->runAtServer();
    - diff --git a/web/app/models/UOJProblem.php b/web/app/models/UOJProblem.php index d520f93..c0bd929 100644 --- a/web/app/models/UOJProblem.php +++ b/web/app/models/UOJProblem.php @@ -52,6 +52,246 @@ class UOJProblem { 3500 => '#aa0000', ]; + public static array $categories = [ + '算法基础' => [ + '暴力', + '枚举', + '模拟', + '递归与分治', + '贪心', + '排序', + '前缀和与差分', + '二分', + '倍增', + '构造', + '打表', + ], + '搜索' => [ + '深度优先搜索', + '广度优先搜索', + '双向搜索', + '启发式搜索', + 'A*', + 'IDA*', + '迭代加深', + '回溯法', + 'Dancing Links', + ], + '动态规划' => [ + '记忆化搜索', + '线性 DP', + '背包 DP', + '区间 DP', + '树形 DP', + '状压 DP', + '数位 DP', + 'DAG 上 DP', + '插头 DP', + '概率 DP', + '单调队列优化 DP', + '斜率优化 DP', + '四边形不等式优化 DP', + ], + '计算几何' => [ + 'Pick 定理', + '三角剖分', + '凸包', + '扫描线', + '旋转卡壳', + '半平面交', + '平面最近点对', + '随机增量法', + '反演变换', + ], + '数学' => [ + '位运算', + '快速幂', + '高精度', + '生成函数', + '指数生成函数', + '向量', + '矩阵', + '高斯消元', + '线性基', + '线性规划', + '容斥', + '组合计数', + '离散对数', + '单纯形算法', + '概率', + '置换群', + '斐波那契数列', + '牛顿迭代法', + '数值积分', + '分块打表', + ], + '数论' => [ + '最大公约数', + '分解质因数', + '欧拉函数', + '筛法', + '欧拉定理', + '费马小定理', + '类欧几里得算法', + '翡蜀定理', + '乘法逆元', + '线性同余方程', + 'Meissel-Lehmer 算法', + '二次剩余', + 'BSGS', + '原根', + '卢卡斯定理', + '莫比乌斯反演', + '拉格朗日反演', + '杜教筛', + 'Powerful Number 筛', + 'Min_25 筛', + '洲阁筛', + '连分数', + 'Stern-Brocot 数与 Farey 序列', + 'Pell 方程', + ], + '字符串' => [ + '字符串哈希', + '字典树', + 'KMP', + 'Boyer-Moore', + 'Z 函数(扩展 KMP)', + 'AC 自动机', + '后缀数组', + '后缀自动机', + '后缀平衡树', + '广义后缀自动机', + 'Manacher', + '回文树', + '序列自动机', + '最小表示法', + 'Lyndon 分解', + ], + '图论' => [ + '拓扑排序', + '最短路', + 'K 短路', + '同余最短路', + '虚树', + '树分治', + '动态树分治', + '树哈希', + '树上启发式合并', + 'AHU 算法', + '矩阵树定理', + '最小生成树', + '最小树形图', + '最小直径生成树', + '斯坦纳树', + '拆点', + '差分约束', + '强连通分量', + '双连通分量', + '割点与桥', + '圆方树', + '2-SAT', + '欧拉图', + '哈密顿图', + '最小环', + '平面图', + '网络流', + '最大流', + '最小割', + '费用流', + '上下界网络流', + 'Stoer-Wagner 算法', + '二分图', + '二分图最大匹配', + '二分图最大权匹配', + '一般图最大匹配', + '一般图最大权匹配', + 'Prufer 序列', + 'LGV 引理', + '弦图', + ], + '组合数学' => [ + '排列组合', + '卡特兰数', + '斯特林数', + '贝尔数', + '伯努利数', + '康托展开', + '容斥原理', + '抽屉原理', + '欧拉数', + ], + '数据结构' => [ + '栈', + '队列', + '链表', + '哈希表', + '并查集', + '二叉堆', + '配对堆', + '树状数组', + '线段树', + '平衡树', + '左偏树', + '块状数组', + '块状链表', + '树分块', + 'Sqrt Tree', + '可持久化数据结构', + '单调栈', + '单调队列', + 'ST 表', + '树套树', + '李超线段树', + '区间最值操作与区间历史最值', + '划分树', + '跳表', + 'K-D Tree', + '珂朵莉树', + '动态树', + '析合树', + ], + '多项式' => [ + '拉格朗日插值', + '快速傅里叶变换', + '快速数论变换', + '快速沃尔什变换', + '多项式求逆', + '多项式开方', + '多项式除法与取模', + '多项式对数函数与指数函数', + '多项式牛顿迭代', + '多项式多点求值与快速插值', + '多项式三角函数', + '多项式反三角函数', + '常系数齐次线性递推', + ], + '博弈论' => [ + '不平等博弈', + 'SG 函数', + 'Nim 游戏', + 'Anti-Nim', + '纳什均衡', + ], + '杂项' => [ + '构造', + '离散化', + 'CDQ 分治', + '整体二分', + '分块', + '莫队', + '分数规划', + '随机化', + '模拟退火', + '爬山法', + '悬线法', + '编译原理', + '复杂度分析', + '语义分析', + '底层优化', + ], + ]; + public static function query($id) { if (!isset($id) || !validateUInt($id)) { return null; diff --git a/web/js/uoj.js b/web/js/uoj.js index e9a8586..61df0fd 100644 --- a/web/js/uoj.js +++ b/web/js/uoj.js @@ -1109,6 +1109,11 @@ $(document).ready(function() { [...document.querySelectorAll('[data-bs-toggle="tooltip"]')].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl)); }); +// Popovers +$(document).ready(function() { + [...document.querySelectorAll('[data-bs-toggle="popover"]')].map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl)); +}); + // Copy button $(document).ready(function() { $('.markdown-body pre, .copy-button-container pre').each(function () { From 71ecc24d19d6bd07b4d099a70273a3be30cc0a47 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Fri, 13 Jan 2023 08:37:20 +0800 Subject: [PATCH 13/30] feat(web/problems): redirect to edit page after create problem --- web/app/controllers/problem_set.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/app/controllers/problem_set.php b/web/app/controllers/problem_set.php index 0edda88..47623eb 100644 --- a/web/app/controllers/problem_set.php +++ b/web/app/controllers/problem_set.php @@ -73,6 +73,9 @@ EOD; ]) ]); dataNewProblem($id); + + redirectTo("/problem/{$id}/manage/statement"); + die(); }; $new_problem_form->submit_button_config['align'] = 'right'; $new_problem_form->submit_button_config['class_str'] = 'btn btn-primary'; From 5f15f832af5ce689d4e356dedcc13f7c8bbe04eb Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sat, 14 Jan 2023 08:44:59 +0800 Subject: [PATCH 14/30] feat(web/problem/solutions): add quick_add_new_solution_form --- web/app/controllers/problem_solutions.php | 39 +++++++++++++++++------ 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/web/app/controllers/problem_solutions.php b/web/app/controllers/problem_solutions.php index 590d5b5..d4cba7f 100644 --- a/web/app/controllers/problem_solutions.php +++ b/web/app/controllers/problem_solutions.php @@ -100,6 +100,29 @@ if (UOJProblem::cur()->userCanManage(Auth::user()) || UOJProblem::cur()->userPer ]); }; $add_new_solution_form->runAtServer(); + + if (UOJUser::checkPermission(Auth::user(), 'blogs.create')) { + $quick_add_new_solution_form = new UOJForm('quick_add_new_solution'); + $quick_add_new_solution_form->config['submit_container']['class'] = ''; + $quick_add_new_solution_form->config['submit_button']['class'] = 'btn btn-link text-decoration-none p-0'; + $quick_add_new_solution_form->config['submit_button']['text'] = '快速新建文章'; + $quick_add_new_solution_form->handle = function () { + DB::insert([ + "insert into blogs", + "(title, content, content_md, poster, is_hidden, post_time, active_time)", + "values", DB::tuple([ + '【题解】' . UOJProblem::cur()->getTitle(), '', '', + Auth::id(), false, DB::now(), DB::now() + ]) + ]); + + $blog_id = DB::insert_id(); + + redirectTo(HTML::blog_url(Auth::id(), "/post/{$blog_id}/write")); + die(); + }; + $quick_add_new_solution_form->runAtServer(); + } } $pag_config = [ @@ -261,18 +284,16 @@ $pag = new Paginator($pag_config); 您当前无法为本题新增题解。 - + + + - - + - + From 6a4f9a370aeca4348f65b538726052a9011f0454 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sat, 14 Jan 2023 08:51:00 +0800 Subject: [PATCH 15/30] feat(web/lists): add redirect after create list --- web/app/controllers/lists.php | 28 ++++++++++++++++++++-------- web/app/models/UOJForm.php | 2 +- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/web/app/controllers/lists.php b/web/app/controllers/lists.php index 2e81ef3..a24c626 100644 --- a/web/app/controllers/lists.php +++ b/web/app/controllers/lists.php @@ -9,16 +9,28 @@ Auth::check() || redirectToLogin(); UOJUser::checkPermission(Auth::user(), 'lists.view') || UOJResponse::page403(); if (UOJList::userCanCreateList(Auth::user())) { - $new_list_form = new UOJBs4Form('new_list'); + $new_list_form = new UOJForm('new_list'); $new_list_form->handle = function () { - DB::insert("insert into lists (title, is_hidden) values ('未命名题单', 1)"); - $id = DB::insert_id(); - DB::insert("insert into lists_contents (id, content, content_md) values ($id, '', '')"); + DB::insert([ + "insert into lists", + DB::bracketed_fields(['title', 'is_hidden']), + "values", + DB::tuple(['未命名题单', 1]), + ]); + $list_id = DB::insert_id(); + DB::insert([ + "insert into lists_contents", + DB::bracketed_fields(['id', 'content', 'content_md']), + "values", + DB::tuple([$list_id, '', '']), + ]); + redirectTo("/list/{$list_id}"); + die(); }; - $new_list_form->submit_button_config['align'] = 'right'; - $new_list_form->submit_button_config['class_str'] = 'btn btn-primary'; - $new_list_form->submit_button_config['text'] = UOJLocale::get('problems::add new list'); - $new_list_form->submit_button_config['smart_confirm'] = ''; + $new_list_form->config['submit_container']['class'] = 'text-end'; + $new_list_form->config['submit_button']['class'] = 'btn btn-primary'; + $new_list_form->config['submit_button']['text'] = UOJLocale::get('problems::add new list'); + $new_list_form->config['confirm']['smart'] = true; $new_list_form->runAtServer(); } diff --git a/web/app/models/UOJForm.php b/web/app/models/UOJForm.php index 05b015b..7923268 100644 --- a/web/app/models/UOJForm.php +++ b/web/app/models/UOJForm.php @@ -346,7 +346,7 @@ class UOJForm { } if ($this->config['confirm']['smart']) { - $this->config['confirm']['text'] = '你真的要' . $this->config['submit']['text'] . '吗?'; + $this->config['confirm']['text'] = '你真的要' . $this->config['submit_button']['text'] . '吗?'; } if ($this->config['confirm']['text']) { echo << Date: Sat, 14 Jan 2023 15:14:05 +0800 Subject: [PATCH 16/30] chore(web/user/edit): not require email --- web/app/controllers/user_info_edit.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app/controllers/user_info_edit.php b/web/app/controllers/user_info_edit.php index f2f6897..7d7dc3a 100644 --- a/web/app/controllers/user_info_edit.php +++ b/web/app/controllers/user_info_edit.php @@ -115,7 +115,7 @@ EOD); UOJLocale::get('email'), $user['email'] ?: '', function ($email, &$vdata) { - if (!validateEmail($email)) { + if ($email && !validateEmail($email)) { return 'Email 格式不合法。'; } From 452c2ca12b35b963a46fe14d5d24be40c742a530 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sat, 14 Jan 2023 17:20:10 +0800 Subject: [PATCH 17/30] feat(web/user): username color Co-authored-by: Wenkuo Yu <82705676+youwike@users.noreply.github.com> Co-authored-by: Baoshuo Ren <47095648+renbaoshuo@users.noreply.github.com> --- web/app/controllers/super_manage.php | 2 +- web/app/controllers/user_info_edit.php | 34 +++++++++++++++++++++++++- web/app/models/UOJUser.php | 34 ++++++++++++++++++++++---- web/css/uoj-bs5.css | 7 +++++- web/js/uoj.js | 9 +++++-- 5 files changed, 76 insertions(+), 10 deletions(-) diff --git a/web/app/controllers/super_manage.php b/web/app/controllers/super_manage.php index 113fb1c..ad04c3e 100644 --- a/web/app/controllers/super_manage.php +++ b/web/app/controllers/super_manage.php @@ -1336,7 +1336,7 @@ EOD); EOD, function ($row) { echo ''; - echo '', '', $row['username'], '', ''; + echo '', UOJUser::getLink($row), ''; echo '', HTML::escape($row['school']), ''; echo ''; switch ($row['usergroup']) { diff --git a/web/app/controllers/user_info_edit.php b/web/app/controllers/user_info_edit.php index 7d7dc3a..2a9dfaf 100644 --- a/web/app/controllers/user_info_edit.php +++ b/web/app/controllers/user_info_edit.php @@ -233,6 +233,36 @@ EOD); }, null ); + if ($user['usergroup'] == 'B') { + $update_profile_form->appendHTML(<< + + +
    被封禁的用户无法修改用户名颜色。
    + + EOD); + } else if ($user['usergroup'] == 'T') { + $update_profile_form->appendHTML(<< + + +
    临时用户无法修改用户名颜色。
    + + EOD); + } else { + $additional_colors = []; + + if (isSuperUser($user)) { + $additional_colors['#9d3dcf'] = '紫色 - #9d3dcf'; + $additional_colors['#fe4c61'] = '红色 - #fe4c61'; + } + + $update_profile_form->addVSelect('username_color', $additional_colors + [ + '#0d6efd' => '蓝色 - #0d6efd', + '#2da44e' => '绿色 - #2da44e', + '#f48fb1' => '粉色 - #f48fb1', + ], '用户名颜色', '#0d6efd'); + } $update_profile_form->handle = function (&$vdata) use ($user) { $data = [ 'email' => $vdata['email'], @@ -268,7 +298,9 @@ EOD); '$.social.codeforces', $vdata['codeforces'], '$.social.website', - $vdata['website'] + $vdata['website'], + '$.username_color', + $_POST['username_color'] ), ], "where", ["username" => $user['username']] diff --git a/web/app/models/UOJUser.php b/web/app/models/UOJUser.php index 46e955e..508305d 100644 --- a/web/app/models/UOJUser.php +++ b/web/app/models/UOJUser.php @@ -221,14 +221,37 @@ class UOJUser { } } - if ($user['usergroup'] == 'B') { - return HTML::tag('a', ['class' => 'text-danger fw-bold', 'href' => "/user/{$user['username']}"], $user['username']); + $extra = UOJUser::getExtra($user); + $realname = $user['realname']; + $color = '#0d6efd'; + + if ($user['usergroup'] === 'B') { + $color = '#996600'; + } else if (isTmpUser($user)) { + $color = '#707070'; + } else { + if (isSuperUser($user)) { + $color = '#9d3dcf'; + } + + $color = $extra['username_color']; + + // 前管理员设置颜色为紫色、红色的,颜色改为蓝色 + if (($color === '#9d3dcf' || $color === '#fe4c61') && !isSuperUser($user)) { + $color = '#0d6efd'; + } } - // 未登录不可查看真实姓名 - $realname = Auth::check() ? $user['realname'] : ''; + if ($user['usertype'] == 'teacher') { + $realname .= '老师'; + } - return HTML::tag('span', ['class' => 'uoj-username', 'data-realname' => trim(HTML::escape($realname))], $user['username']); + return HTML::tag('span', [ + 'class' => 'uoj-username', + // 未登录不可查看真实姓名 + 'data-realname' => Auth::check() ? trim(HTML::escape($realname)) : '', + 'data-color' => $color, + ], $user['username']); } public static function getUpdatedExtraVisitHistory($history, $cur) { @@ -290,6 +313,7 @@ class UOJUser { 'show_email' => 'all', 'show_qq' => 'all', 'avatar_source' => 'gravatar', + 'username_color' => isSuperUser($user) ? '#9d3dcf' : '#0d6efd', ]); return $extra; } diff --git a/web/css/uoj-bs5.css b/web/css/uoj-bs5.css index 6d35ca9..1019f61 100644 --- a/web/css/uoj-bs5.css +++ b/web/css/uoj-bs5.css @@ -25,6 +25,11 @@ a { 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; } +.uoj-realname { + font-size: 90%; + font-weight: normal; +} + h1, .h1 { /* font-size: 2.5rem; */ @@ -164,7 +169,7 @@ h6, .card-uoj-tle > .card-header:hover, .card-uoj-tle > div.card-header > div > .uoj-status-text { - color: sandybrown; + color: #f4a460; } .card-uoj-wrong > .card-header:hover, diff --git a/web/js/uoj.js b/web/js/uoj.js index 61df0fd..267f608 100644 --- a/web/js/uoj.js +++ b/web/js/uoj.js @@ -148,11 +148,16 @@ function getUserSpan(username, realname) { function replaceWithHighlightUsername() { var username = $(this).text(); var realname = $(this).data("realname"); + var color = $(this).data("color"); + var new_elem_inner = ''; + if ($(this).data("link") != 0) { - $(this).replaceWith(getUserLink(username, realname)); + new_elem_inner = getUserLink(username, realname); } else { - $(this).replaceWith(getUserSpan(username, realname)); + new_elem_inner = getUserSpan(username, realname); } + + $(this).replaceWith($(new_elem_inner).css('color', color)); } $.fn.uoj_honor = function() { From 75edc82b28bf5f2f186dbcf95dcf507b4ff9b65a Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sat, 14 Jan 2023 17:53:34 +0800 Subject: [PATCH 18/30] fix(web/user/edit): username_color default_value --- web/app/controllers/user_info_edit.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app/controllers/user_info_edit.php b/web/app/controllers/user_info_edit.php index 2a9dfaf..e714e20 100644 --- a/web/app/controllers/user_info_edit.php +++ b/web/app/controllers/user_info_edit.php @@ -261,7 +261,7 @@ EOD); '#0d6efd' => '蓝色 - #0d6efd', '#2da44e' => '绿色 - #2da44e', '#f48fb1' => '粉色 - #f48fb1', - ], '用户名颜色', '#0d6efd'); + ], '用户名颜色', $extra['username_color']); } $update_profile_form->handle = function (&$vdata) use ($user) { $data = [ From 1ebcda02d6151118cd1f250ea482b70ef79f98df Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sat, 14 Jan 2023 18:24:03 +0800 Subject: [PATCH 19/30] feat(web/contest): username color --- web/app/libs/uoj-contest-lib.php | 27 +++++++++++---- web/app/models/UOJUser.php | 54 ++++++++++++++++++----------- web/app/views/contest-standings.php | 2 +- web/js/uoj.js | 23 +++++++----- 4 files changed, 68 insertions(+), 38 deletions(-) diff --git a/web/app/libs/uoj-contest-lib.php b/web/app/libs/uoj-contest-lib.php index 1b53904..f360bf0 100644 --- a/web/app/libs/uoj-contest-lib.php +++ b/web/app/libs/uoj-contest-lib.php @@ -87,14 +87,23 @@ function queryContestData($contest, $config = []) { $people = []; if ($contest['extra_config']['individual_or_team'] == 'individual') { - $people = DB::selectAll([ - "select contests_registrants.username, user_info.realname from contests_registrants", + $res = DB::selectAll([ + "select contests_registrants.username, user_info.realname, user_info.extra, user_info.usergroup from contests_registrants", "inner join user_info on contests_registrants.username = user_info.username", "where", [ "contest_id" => $contest['id'], "has_participated" => 1 ] ], DB::NUM); + foreach ($res as $row) { + $extra = json_decode($row[2], true); + $people[] = [ + $row[0], + trim(HTML::escape($row[1])), + null, + UOJUser::getUserColor2($row[3], $extra['username_color']), + ]; + } } elseif ($contest['extra_config']['individual_or_team'] == 'team') { $res = DB::selectAll([ "select user_info.username, null, user_info.extra from contests_registrants, user_info", @@ -106,11 +115,15 @@ function queryContestData($contest, $config = []) { ], DB::NUM); foreach ($res as $row) { $extra = json_decode($row[2], true); - $row[2] = [ - 'team_name' => $extra['acm']['team_name'], - 'members' => $extra['acm']['members'] + $people[] = [ + $row[0], + null, + [ + 'team_name' => $extra['acm']['team_name'], + 'members' => $extra['acm']['members'], + ], + null, ]; - $people[] = $row; } } @@ -373,7 +386,7 @@ function calcStandings($contest, $contest_data, &$score, &$standings, $cfg = []) } } - // standings: rank => score, penalty, [username, realname], virtual_rank, ?review + // standings: rank => score, penalty, [username, realname, null|array, null|color], virtual_rank, ?review $standings = []; foreach ($contest_data['people'] as $person) { $cur = array(0, 0, $person); diff --git a/web/app/models/UOJUser.php b/web/app/models/UOJUser.php index 508305d..388b724 100644 --- a/web/app/models/UOJUser.php +++ b/web/app/models/UOJUser.php @@ -210,6 +210,33 @@ class UOJUser { } } + public static function getUserColor($user) { + $extra = UOJUser::getExtra($user); + + return UOJUser::getUserColor2($user['usergroup'], $extra['username_color']); + } + + public static function getUserColor2($usergroup, $custom_color = null) { + if ($usergroup == 'B') { + return '#996600'; + } + + if ($usergroup == 'T') { + return '#707070'; + } + + if ($usergroup == 'S') { + return $custom_color ?: '#9d3dcf'; + } + + // 前管理员设置颜色为紫色、红色的,颜色改为蓝色 + if ($custom_color == '#9d3dcf' || $custom_color == '#fe4c61') { + return '#0d6efd'; + } + + return $custom_color ?: '#0d6efd'; + } + public static function getLink($user) { if (is_string($user)) { $info = UOJUser::query($user); @@ -221,36 +248,21 @@ class UOJUser { } } - $extra = UOJUser::getExtra($user); $realname = $user['realname']; - $color = '#0d6efd'; - - if ($user['usergroup'] === 'B') { - $color = '#996600'; - } else if (isTmpUser($user)) { - $color = '#707070'; - } else { - if (isSuperUser($user)) { - $color = '#9d3dcf'; - } - - $color = $extra['username_color']; - - // 前管理员设置颜色为紫色、红色的,颜色改为蓝色 - if (($color === '#9d3dcf' || $color === '#fe4c61') && !isSuperUser($user)) { - $color = '#0d6efd'; - } - } if ($user['usertype'] == 'teacher') { $realname .= '老师'; } + if (!Auth::check()) { + $realname = ''; + } + return HTML::tag('span', [ 'class' => 'uoj-username', + 'data-color' => UOJUser::getUserColor($user), // 未登录不可查看真实姓名 - 'data-realname' => Auth::check() ? trim(HTML::escape($realname)) : '', - 'data-color' => $color, + 'data-realname' => trim(HTML::escape($realname)), ], $user['username']); } diff --git a/web/app/views/contest-standings.php b/web/app/views/contest-standings.php index 35ee895..b5240f8 100644 --- a/web/app/views/contest-standings.php +++ b/web/app/views/contest-standings.php @@ -35,7 +35,7 @@ function(row) { var col_tr = ''; col_tr += '' + row[3] + ''; - col_tr += '' + getUserLink(row[2][0], row[2][1]) + ''; + col_tr += '' + getUserLink(row[2][0], row[2][1], row[2][3]) + ''; col_tr += '' + '
    ' + row[0] + '
    ' + '
    ' + getPenaltyTimeStr(row[1]) + '
    '; for (var i = 0; i < problems.length; i++) { col = score[row[2][0]][i]; diff --git a/web/js/uoj.js b/web/js/uoj.js index 267f608..000af78 100644 --- a/web/js/uoj.js +++ b/web/js/uoj.js @@ -118,46 +118,51 @@ function getColOfScore(score) { } } -function getUserLink(username, realname) { +function getUserLink(username, realname, color) { if (!username) { return ''; } var text = username; + var style = ''; if (username.charAt(0) == '@') { username = username.substr(1); } if (realname) { text = text + ' (' + realname + ')'; } - return '' + text + ''; + if (color) { + style += 'color: ' + color + ';'; + } + return '' + text + ''; } -function getUserSpan(username, realname) { +function getUserSpan(username, realname, color) { if (!username) { return ''; } var text = username; + var style = ''; if (username.charAt(0) == '@') { username = username.substr(1); } if (realname) { text = text + ' (' + realname + ')'; } - return '' + text + ''; + if (color) { + style += 'color: ' + color + ';'; + } + return '' + text + ''; } function replaceWithHighlightUsername() { var username = $(this).text(); var realname = $(this).data("realname"); var color = $(this).data("color"); - var new_elem_inner = ''; if ($(this).data("link") != 0) { - new_elem_inner = getUserLink(username, realname); + $(this).replaceWith(getUserLink(username, realname, color)); } else { - new_elem_inner = getUserSpan(username, realname); + $(this).replaceWith(getUserSpan(username, realname, color)); } - - $(this).replaceWith($(new_elem_inner).css('color', color)); } $.fn.uoj_honor = function() { From 4e5d2dee4974c897d472f76e003577127ef5d432 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sat, 14 Jan 2023 18:24:36 +0800 Subject: [PATCH 20/30] feat(web/blog): username color --- web/app/controllers/subdomain/blog/blog.php | 4 +++- web/js/uoj.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/web/app/controllers/subdomain/blog/blog.php b/web/app/controllers/subdomain/blog/blog.php index 5150047..9399add 100644 --- a/web/app/controllers/subdomain/blog/blog.php +++ b/web/app/controllers/subdomain/blog/blog.php @@ -201,7 +201,9 @@ $comments_pag = new Paginator([ "order by id" ]); foreach ($replies as $idx => $reply) { - $replies[$idx]['poster_realname'] = UOJUser::query($reply['poster'])['realname']; + $reply_user = UOJUser::query($reply['poster']); + $replies[$idx]['poster_realname'] = $reply_user['realname']; + $replies[$idx]['poster_username_color'] = UOJUser::getUserColor($reply_user); $replies[$idx]['content'] = getCommentContentToDisplay($reply); } $replies_json = json_encode($replies); diff --git a/web/js/uoj.js b/web/js/uoj.js index 000af78..3b209f3 100644 --- a/web/js/uoj.js +++ b/web/js/uoj.js @@ -1092,7 +1092,7 @@ function showCommentReplies(id, replies) { function(reply) { return $('').append( $('').append( - $('
    ' + getUserLink(reply.poster, reply.poster_realname) + ':' + reply.content + '
    ') + $('
    ' + getUserLink(reply.poster, reply.poster_realname, reply.poster_username_color) + ':' + reply.content + '
    ') ).append( $('
      ').append( '
    • ' + '' + reply.post_time + '' + '
    • ' From c0b442ece07d735b93eeaf9183ca16664e71f6cd Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sat, 14 Jan 2023 18:45:36 +0800 Subject: [PATCH 21/30] fix: 17fbb2c910360dd00325547e455e7087a6619d74 --- web/app/controllers/image_hosting/index.php | 486 -------------------- 1 file changed, 486 deletions(-) delete mode 100644 web/app/controllers/image_hosting/index.php diff --git a/web/app/controllers/image_hosting/index.php b/web/app/controllers/image_hosting/index.php deleted file mode 100644 index 759e9fc..0000000 --- a/web/app/controllers/image_hosting/index.php +++ /dev/null @@ -1,486 +0,0 @@ - Auth::id(), - ], -]); -$count = DB::selectCount([ - "select count(*)", - "from users_images", - "where", [ - "uploader" => Auth::id(), - ], -]); - -function throwError($msg) { - dieWithJsonData(['status' => 'error', 'message' => $msg]); -} - -$allowedTypes = [IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_WEBP]; -if ($_POST['image_upload_file_submit'] == 'submit') { - if (!crsf_check()) { - throwError('expired'); - } - - if (!isset($_SESSION['phrase']) || !PhraseBuilder::comparePhrases($_SESSION['phrase'], $_POST['captcha'])) { - throwError("bad_captcha"); - } - - if ($_FILES["image_upload_file"]["error"] > 0) { - throwError($_FILES["image_upload_file"]["error"]); - } - - if ($_FILES["image_upload_file"]["size"] > 5242880) { // 5 MB - throwError('too_large'); - } - - if ($used + $_FILES["image_upload_file"]["size"] > $limit) { - throwError('storage_limit_exceeded'); - } - - $size = getimagesize($_FILES['image_upload_file']['tmp_name']); - - if (!$size || !in_array($size[2], $allowedTypes)) { - throwError('not_a_image'); - } - - list($width, $height, $type) = $size; - $hash = hash_file("sha256", $_FILES['image_upload_file']['tmp_name']) . Auth::id(); - $scale = ceil($width / 600.0); - - $watermark_text = UOJConfig::$data['profile']['oj-name-short']; - if (isSuperUser(Auth::user()) && $_POST['watermark'] == 'no_watermark') { - $watermark_text = ""; - $hash .= "__no_watermark"; - } elseif ($_POST['watermark'] == 'site_shortname_and_username') { - $watermark_text .= ' @' . Auth::id(); - $hash .= "__id"; - } - - $existing_image = DB::selectFirst("SELECT * FROM users_images WHERE `hash` = '$hash'"); - - if ($existing_image) { - dieWithJsonData(['status' => 'success', 'path' => $existing_image['path']]); - } - - $image = new Imagick($_FILES["image_upload_file"]["tmp_name"]); - $draw = new ImagickDraw(); - $draw->setFont(UOJContext::documentRoot() . '/fonts/roboto-mono/RobotoMono-Bold.ttf'); - $draw->setFontSize($scale * 14); - $draw->setGravity(Imagick::GRAVITY_SOUTHEAST); - $draw->setFillColor("rgba(100,100,100,0.5)"); - $image->annotateImage($draw, 15, 10, 0, $watermark_text); - $draw->setFillColor("rgba(255,255,255,0.65)"); - $image->annotateImage($draw, 15 + $scale, 10 + $scale, 0, $watermark_text); - $image->setImageFormat('png'); - $image->writeImage(); - - if (($size = filesize($_FILES["image_upload_file"]["tmp_name"])) > 5242880) { // 5 MB - throwError('too_large'); - } - - $filename = uojRandAvaiableFileName('/image_hosting/', 10, '.png'); - if (!move_uploaded_file($_FILES["image_upload_file"]["tmp_name"], UOJContext::storagePath() . $filename)) { - throwError('unknown error'); - } - - DB::insert([ - "insert into users_images", - DB::bracketed_fields(["path", "uploader", "width", "height", "upload_time", "size", "hash"]), - "values", DB::tuple([ - $filename, - Auth::id(), - $width, - $height, - DB::now(), - $_FILES["image_upload_file"]["size"], - $hash, - ]), - ]); - - dieWithJsonData(['status' => 'success', 'path' => $filename]); -} elseif ($_POST['image_delete_submit'] == 'submit') { - crsf_defend(); - - $id = $_POST['image_delete_id']; - if (!validateUInt($id)) { - becomeMsgPage('ID 不合法。返回'); - } else { - $result = DB::selectFirst("SELECT * from users_images WHERE id = $id"); - if (!$result) { - becomeMsgPage('图片不存在。返回'); - } else { - unlink(UOJContext::storagePath() . $result['path']); - DB::delete("DELETE FROM users_images WHERE id = $id"); - - header("Location: " . UOJContext::requestURI()); - die(); - } - } -} -?> - - - - - -

      - -

      - -
      -
      -
      -
      - - 点击此处选择图片 -
      - - -
      -

      水印

      - -
      - - -
      - -
      - - -
      -
      - - -
      -
      -
      -

      上传须知

      -
        -
      • 上传的图片必须符合法律与社会道德;
      • -
      • 图床仅供 S2OJ 站内使用,校外用户无法查看;
      • -
      • 图片上传后会被自动转码为 PNG 格式;
      • -
      • 在合适的地方插入图片即可引用。
      • -
      -

      更多信息可以查看 使用文档

      -
      -
      -

      使用统计

      -
      - 已用空间 - MB / MB -
      -
      - 上传总数 - -
      -
      -
      -
      -
      -
      - -
      - - - 40, - 'col_names' => ['*'], - 'table_name' => 'users_images', - 'cond' => "uploader = '{$myUser['username']}'", - 'tail' => 'order by upload_time desc', -]; -$pag = new Paginator($pag_config); -?> - -

      - 我的图片 -

      - -
      - get() as $idx => $row) : ?> -
      -
      - - -
      -
      - -
      - -isEmpty()) : ?> -
      - -
      - - -
      - pagination() ?> -
      - -
      - -
      - - - - From 6dcd43b9144994df94df0af5cfdd7e9140edea02 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sun, 15 Jan 2023 09:15:30 +0800 Subject: [PATCH 22/30] feat(user): more username colors --- web/app/controllers/user_info_edit.php | 6 ++++-- web/app/models/UOJUser.php | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/web/app/controllers/user_info_edit.php b/web/app/controllers/user_info_edit.php index e714e20..bcf9063 100644 --- a/web/app/controllers/user_info_edit.php +++ b/web/app/controllers/user_info_edit.php @@ -254,13 +254,15 @@ EOD); if (isSuperUser($user)) { $additional_colors['#9d3dcf'] = '紫色 - #9d3dcf'; - $additional_colors['#fe4c61'] = '红色 - #fe4c61'; } $update_profile_form->addVSelect('username_color', $additional_colors + [ '#0d6efd' => '蓝色 - #0d6efd', '#2da44e' => '绿色 - #2da44e', - '#f48fb1' => '粉色 - #f48fb1', + '#e85aad' => '粉色 - #e85aad', + '#f32a38' => '红色 - #f32a38', + '#f57c00' => '橙色 - #f57c00', + '#00acc1' => '青色 - #00acc1', ], '用户名颜色', $extra['username_color']); } $update_profile_form->handle = function (&$vdata) use ($user) { diff --git a/web/app/models/UOJUser.php b/web/app/models/UOJUser.php index 388b724..fe45d7f 100644 --- a/web/app/models/UOJUser.php +++ b/web/app/models/UOJUser.php @@ -229,8 +229,8 @@ class UOJUser { return $custom_color ?: '#9d3dcf'; } - // 前管理员设置颜色为紫色、红色的,颜色改为蓝色 - if ($custom_color == '#9d3dcf' || $custom_color == '#fe4c61') { + // 前管理员设置颜色为紫色的,颜色改为蓝色 + if ($custom_color == '#9d3dcf') { return '#0d6efd'; } From be7510a6bb24da2aeb85314e1c896b4779c857b6 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sun, 15 Jan 2023 09:38:29 +0800 Subject: [PATCH 23/30] feat(super_manage): allow change usergroup to temp user --- web/app/controllers/super_manage.php | 58 +++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/web/app/controllers/super_manage.php b/web/app/controllers/super_manage.php index ad04c3e..c5a61e7 100644 --- a/web/app/controllers/super_manage.php +++ b/web/app/controllers/super_manage.php @@ -516,7 +516,7 @@ EOD); 'new_tmp_expiration_time', 'text', '过期时间', - (new DateTime())->add(new DateInterval('P7D'))->format('Y-m-d H:i:s'), + UOJTime::time2str((new DateTime())->add(new DateInterval('P7D'))->setTime(0, 0, 0)), function ($str, &$vdata) { try { $vdata['expiration_time'] = new DateTime($str); @@ -657,6 +657,7 @@ EOD); ); $change_usergroup_form->addVSelect('op_type', [ 'banneduser' => '设为封禁用户', + 'tempuser' => '设为临时用户', 'normaluser' => '设为普通用户', 'superuser' => '设为超级用户', ], '操作类型', ''); @@ -666,15 +667,59 @@ EOD); switch ($_POST['op_type']) { case 'banneduser': - DB::update("update user_info set usergroup = 'B', usertype = 'banned' where username = '{$username}'"); - $usergroup = '被封禁的用户'; + DB::update([ + "update user_info", + "set", [ + "usergroup" => "B", + "usertype" => "banned", + "expiration_time" => null, + ], + "where", [ + "username" => $username, + ], + ]); + $usergroup = '被封禁的用户,该用户将无法再次登录系统'; + break; + case 'tempuser': + DB::update([ + "update user_info", + "set", [ + "usergroup" => "T", + "usertype" => "student", + "expiration_time" => DB::now(), + ], + "where", [ + "username" => $username, + ], + ]); + $usergroup = '临时用户,请前往个人信息编辑页面修改过期时间'; break; case 'normaluser': - DB::update("update user_info set usergroup = 'U', usertype = 'student' where username = '{$username}'"); + DB::update([ + "update user_info", + "set", [ + "usergroup" => "U", + "usertype" => "student", + "expiration_time" => null, + ], + "where", [ + "username" => $username, + ], + ]); $usergroup = '普通用户'; break; case 'superuser': - DB::update("update user_info set usergroup = 'S', usertype = 'student' where username = '{$username}'"); + DB::update([ + "update user_info", + "set", [ + "usergroup" => "S", + "usertype" => "student", + "expiration_time" => null, + ], + "where", [ + "username" => $username, + ], + ]); $usergroup = '超级用户'; break; } @@ -1429,7 +1474,8 @@ EOD);
      注意事项
      • 用户被封禁后将不能再次登录系统。
      • -
      • 将当前用户移除权限后将无法再次访问本页面。
      • +
      • 将用户修改为临时用户后,请前往个人信息编辑页面修改过期时间。
      • +
      • 将当前用户移除管理权限后将无法再次访问本页面。
      • 在修改用户类别前请仔细核对用户名以免产生不必要的麻烦。
      • 如需为用户设置题目上传者、题目管理员等权限,请前往对应用户的个人资料编辑页面,点击「特权」选项卡修改。
      From 6548c2e2b725ad31ca22b81895263bcd6db012f0 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sun, 15 Jan 2023 11:13:43 +0800 Subject: [PATCH 24/30] fix: username color in md mention --- web/app/controllers/group.php | 2 +- .../subdomain/blog/self_reviews.php | 2 +- web/app/libs/uoj-html-lib.php | 56 ------------- web/app/models/HTML.php | 16 +++- web/app/models/UOJMarkdown.php | 80 +++++++++++-------- web/app/models/UOJRanklist.php | 4 +- web/app/models/UOJUser.php | 18 +++-- web/app/vendor/erusev/parsedown/Parsedown.php | 2 + web/app/views/contest-reviews.php | 2 +- web/app/views/sidebar.php | 2 +- web/app/views/user-info.php | 2 +- 11 files changed, 78 insertions(+), 108 deletions(-) diff --git a/web/app/controllers/group.php b/web/app/controllers/group.php index 8bde983..82e4eed 100644 --- a/web/app/controllers/group.php +++ b/web/app/controllers/group.php @@ -49,7 +49,7 @@ UOJGroup::cur()->userCanView(Auth::user(), ['ensure' => true]);
      - purify(HTML::parsedown()->line(UOJGroup::info('announcement'))) ?> + purify(HTML::parsedown(['username_with_color' => true])->line(UOJGroup::info('announcement'))) ?>
      diff --git a/web/app/controllers/subdomain/blog/self_reviews.php b/web/app/controllers/subdomain/blog/self_reviews.php index 894a394..60f6652 100644 --- a/web/app/controllers/subdomain/blog/self_reviews.php +++ b/web/app/controllers/subdomain/blog/self_reviews.php @@ -32,7 +32,7 @@ $header_row .= '' . UOJLocale::get('contests::problem sel $header_row .= '' . UOJLocale::get('contests::contest self review') . ''; $header_row .= ''; -$parsedown = HTML::parsedown(); +$parsedown = HTML::parsedown(['username_with_color' => true]); $purifier = HTML::purifier_inline(); $print_row = function ($row) use ($parsedown, $purifier) { diff --git a/web/app/libs/uoj-html-lib.php b/web/app/libs/uoj-html-lib.php index 1eb63f3..02242c0 100644 --- a/web/app/libs/uoj-html-lib.php +++ b/web/app/libs/uoj-html-lib.php @@ -1009,62 +1009,6 @@ function echoUOJPageFooter($config = array()) { uojIncludeView('page-footer', $config); } -function echoRanklist($config = []) { - $header_row = ''; - $header_row .= ''; - $header_row .= '#'; - $header_row .= '' . UOJLocale::get('username') . ''; - $header_row .= '' . UOJLocale::get('motto') . ''; - $header_row .= '' . UOJLocale::get('solved') . ''; - $header_row .= ''; - - $parsedown = HTML::parsedown(); - $purifier = HTML::purifier_inline(); - $users = []; - $print_row = function ($user, $now_cnt) use (&$users, $config, $purifier, $parsedown) { - if (!$users) { - if ($now_cnt == 1) { - $rank = 1; - } else { - $rank = DB::selectCount("select count(*) from (select b.username as username, count(*) as accepted from best_ac_submissions a inner join user_info b on a.submitter = b.username group by username) as derived where accepted > {$user['ac_num']}") + 1; - } - } else { - $rank = $now_cnt; - } - - $user['rank'] = $rank; - - echo ''; - echo '' . $user['rank'] . ''; - echo '' . UOJUser::getLink($user['username']) . ''; - echo ""; - echo $purifier->purify($parsedown->line($user['motto'])); - echo ""; - echo '' . $user['ac_num'] . ''; - echo ''; - - $users[] = $user; - }; - - $from = 'user_info'; - $col_names = ['user_info.username as username', 'ac_num', 'motto']; - $cond = '1'; - $tail = 'group by user_info.username order by ac_num desc, user_info.username asc'; - - if (isset($config['group_id'])) { - $group_id = $config['group_id']; - $from = "user_info inner join groups_users on (user_info.username = groups_users.username and groups_users.group_id = {$group_id})"; - $config['pagination_cond'] = "group_id = {$group_id}"; - } - - if (isset($config['top10'])) { - $tail .= ' limit 10'; - } - - $config['get_row_index'] = ''; - echoLongTable($col_names, $from, $cond, $tail, $header_row, $print_row, $config); -} - // ===== uoj.ac ===== function echoJudgmentDetails($raw_details, $styler, $name) { diff --git a/web/app/models/HTML.php b/web/app/models/HTML.php index 537a8e0..df75d89 100644 --- a/web/app/models/HTML.php +++ b/web/app/models/HTML.php @@ -436,7 +436,11 @@ class HTML { $def->addElement('footer', 'Block', 'Flow', 'Common'); $extra_allowed_html = [ - 'span' => ['data-realname' => 'Text', 'data-uoj-username' => 'Number'], + 'span' => [ + 'class' => 'Enum#uoj-username', + 'data-realname' => 'Text', + 'data-color' => 'Color', + ], 'img' => ['width' => 'Text'], ]; @@ -463,7 +467,11 @@ class HTML { 'small' => [], 'del' => [], 'br' => [], - 'span' => ['data-realname' => 'Text', 'data-uoj-username' => 'Number'], + 'span' => [ + 'class' => 'Enum#uoj-username', + 'data-realname' => 'Text', + 'data-color' => 'Color', + ], ]; $allowed_elements = []; @@ -490,8 +498,8 @@ class HTML { return new HTMLPurifier($config); } - public static function parsedown() { - return new UOJMarkdown([ + public static function parsedown($config = []) { + return new UOJMarkdown($config + [ 'math' => [ 'enabled' => true, 'matchSingleDollar' => true diff --git a/web/app/models/UOJMarkdown.php b/web/app/models/UOJMarkdown.php index e4f32d7..6528f81 100644 --- a/web/app/models/UOJMarkdown.php +++ b/web/app/models/UOJMarkdown.php @@ -1,10 +1,12 @@ options['username_with_color'] = $options['username_with_color'] ?: false; + // https://gist.github.com/ShNURoK42/b5ce8baa570975db487c $this->InlineTypes['@'][] = 'UserMention'; $this->inlineMarkerList .= '@'; @@ -19,18 +21,18 @@ class UOJMarkdown extends ParsedownMath { } // https://github.com/taufik-nurrohman/parsedown-extra-plugin/blob/1653418c5a9cf5277cd28b0b23ba2d95d18e9bc4/ParsedownExtraPlugin.php#L347-L358 - protected function doGetContent($Element) { - if (isset($Element['text'])) { - return $Element['text']; - } - if (isset($Element['rawHtml'])) { - return $Element['rawHtml']; - } - if (isset($Element['handler']['argument'])) { - return implode("\n", (array) $Element['handler']['argument']); - } - return null; - } + protected function doGetContent($Element) { + if (isset($Element['text'])) { + return $Element['text']; + } + if (isset($Element['rawHtml'])) { + return $Element['rawHtml']; + } + if (isset($Element['handler']['argument'])) { + return implode("\n", (array) $Element['handler']['argument']); + } + return null; + } // https://github.com/taufik-nurrohman/parsedown-extra-plugin/blob/1653418c5a9cf5277cd28b0b23ba2d95d18e9bc4/ParsedownExtraPlugin.php#L369-L378 protected function doSetAttributes(&$Element, $From, $Args = array()) { @@ -52,27 +54,35 @@ class UOJMarkdown extends ParsedownMath { } // https://gist.github.com/ShNURoK42/b5ce8baa570975db487c - protected function inlineUserMention($Excerpt) { - if (preg_match('/^@([^\s]+)/', $Excerpt['text'], $matches)) { - if (($user = UOJUser::query($matches[1])) && $user['usergroup'] != 'B') { - return [ - 'extent' => strlen($matches[0]), - 'element' => [ - 'name' => 'span', - 'text' => '@' . $user['username'], - 'attributes' => [ - 'class' => 'uoj-username', - 'data-realname' => $user['realname'], - 'data-uoj-username' => 1, - ], - ], - ]; - } + protected function inlineUserMention($Excerpt) { + if (preg_match('/^@([^\s]+)/', $Excerpt['text'], $matches)) { + $mentioned_user = UOJUser::query($matches[1]); - return [ - 'extent' => strlen($matches[0]), - 'markup' => $matches[0], - ]; - } - } + if ($mentioned_user) { + $color = '#0d6efd'; + + if ($this->options['username_with_color']) { + $color = UOJUser::getUserColor($mentioned_user); + } + + return [ + 'extent' => strlen($matches[0]), + 'element' => [ + 'name' => 'span', + 'text' => '@' . $mentioned_user['username'], + 'attributes' => [ + 'class' => 'uoj-username', + 'data-realname' => UOJUser::getRealname($mentioned_user), + 'data-color' => $color, + ], + ], + ]; + } + + return [ + 'extent' => strlen($matches[0]), + 'markup' => $matches[0], + ]; + } + } } diff --git a/web/app/models/UOJRanklist.php b/web/app/models/UOJRanklist.php index 2aadd7a..b423fc7 100644 --- a/web/app/models/UOJRanklist.php +++ b/web/app/models/UOJRanklist.php @@ -22,7 +22,7 @@ class UOJRanklist { } $last_user = null; - $parsedown = HTML::parsedown(); + $parsedown = HTML::parsedown(['username_with_color' => true]); $purifier = HTML::purifier_inline(); $print_row = function ($user, $now_cnt) use (&$last_user, &$conds, &$parsedown, &$purifier) { if ($last_user === null) { @@ -138,7 +138,7 @@ class UOJRanklist { $header_row .= ''; $last_user = null; - $parsedown = HTML::parsedown(); + $parsedown = HTML::parsedown(['username_with_color' => true]); $purifier = HTML::purifier_inline(); $print_row = function ($user, $now_cnt) use (&$last_user, &$conds, &$parsedown, &$purifier) { if ($last_user === null) { diff --git a/web/app/models/UOJUser.php b/web/app/models/UOJUser.php index fe45d7f..d86d1f3 100644 --- a/web/app/models/UOJUser.php +++ b/web/app/models/UOJUser.php @@ -210,6 +210,16 @@ class UOJUser { } } + public static function getRealname($user) { + $realname = $user['realname']; + + if ($user['usertype'] == 'teacher') { + $realname .= '老师'; + } + + return $realname; + } + public static function getUserColor($user) { $extra = UOJUser::getExtra($user); @@ -248,12 +258,9 @@ class UOJUser { } } - $realname = $user['realname']; - - if ($user['usertype'] == 'teacher') { - $realname .= '老师'; - } + $realname = UOJUser::getRealname($user); + // 未登录不可查看真实姓名 if (!Auth::check()) { $realname = ''; } @@ -261,7 +268,6 @@ class UOJUser { return HTML::tag('span', [ 'class' => 'uoj-username', 'data-color' => UOJUser::getUserColor($user), - // 未登录不可查看真实姓名 'data-realname' => trim(HTML::escape($realname)), ], $user['username']); } diff --git a/web/app/vendor/erusev/parsedown/Parsedown.php b/web/app/vendor/erusev/parsedown/Parsedown.php index 1b9d6d5..9f7eb5f 100644 --- a/web/app/vendor/erusev/parsedown/Parsedown.php +++ b/web/app/vendor/erusev/parsedown/Parsedown.php @@ -19,6 +19,8 @@ class Parsedown const version = '1.7.4'; + protected $options = []; + # ~ function text($text) diff --git a/web/app/views/contest-reviews.php b/web/app/views/contest-reviews.php index 7b73701..d0478e0 100644 --- a/web/app/views/contest-reviews.php +++ b/web/app/views/contest-reviews.php @@ -1,7 +1,7 @@ true]); $purifier = HTML::purifier_inline(); foreach ($contest_data['people'] as $person) { diff --git a/web/app/views/sidebar.php b/web/app/views/sidebar.php index 956c64a..1923266 100644 --- a/web/app/views/sidebar.php +++ b/web/app/views/sidebar.php @@ -1,6 +1,6 @@ true]); ?> diff --git a/web/app/views/user-info.php b/web/app/views/user-info.php index 36623be..48375e1 100644 --- a/web/app/views/user-info.php +++ b/web/app/views/user-info.php @@ -21,7 +21,7 @@
      - purify(HTML::parsedown()->line($user['motto'])) ?> + purify(HTML::parsedown(['username_with_color' => true])->line($user['motto'])) ?>
        From 3c2ab13e0dd3ed3be9db68295fb8ae319a6e09cd Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sun, 15 Jan 2023 15:12:42 +0800 Subject: [PATCH 25/30] fix(list/manage): remove dup problem id --- web/app/controllers/list_manage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app/controllers/list_manage.php b/web/app/controllers/list_manage.php index 757c722..c158934 100644 --- a/web/app/controllers/list_manage.php +++ b/web/app/controllers/list_manage.php @@ -318,7 +318,7 @@ EOD); echo HTML::tag_begin('tr'); echo HTML::tag('td', ['class' => 'text-center'], $problem->info['id']); echo HTML::tag_begin('td'); - echo $problem->getLink(); + echo $problem->getLink(['with' => 'none']); if ($problem->info['is_hidden']) { echo ' ', UOJLocale::get('hidden'), ' '; } From fadf7225270349b4678681afd5dfb73abc942aa4 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sun, 15 Jan 2023 18:53:06 +0800 Subject: [PATCH 26/30] feat: mount config file instead of passing env --- .config.php | 45 ++++++++++++++++++++++++++++++++++ .gitignore | 1 + docker-compose.development.yml | 11 +-------- docker-compose.yml | 11 +-------- web/app/.default-config.php | 20 +++++++-------- web/install.sh | 11 --------- 6 files changed, 58 insertions(+), 41 deletions(-) create mode 100644 .config.php diff --git a/.config.php b/.config.php new file mode 100644 index 0000000..74a55c9 --- /dev/null +++ b/.config.php @@ -0,0 +1,45 @@ + [ + 'oj-name' => '石家庄二中信息学在线评测系统', + 'oj-name-short' => 'S2OJ', + 'administrator' => 'root', + 'admin-email' => 'admin@sjzezoj.com', + 'QQ-group' => '', + 'ICP-license' => '冀ICP备2020028886号', + ], + 'database' => [ + 'database' => 'app_uoj233', + 'username' => 'root', + 'password' => 'root', + 'host' => 'uoj-db', + 'port' => '3306', + ], + 'security' => [ + 'user' => [ + 'client_salt' => 'salt_0', + ], + 'cookie' => [ + 'checksum_salt' => ['salt_1', 'salt_2', 'salt_3'], + ], + ], + 'mail' => [ + 'noreply' => [ + 'username' => 'noreply@local_uoj.ac', + 'password' => '_mail_noreply_password_', + 'host' => 'smtp.local_uoj.ac', + 'secure' => 'tls', + 'port' => 587, + ] + ], + 'judger' => [ + 'socket' => [ + 'port' => '2333', + 'password' => '_judger_socket_password_' + ], + ], + 'switch' => [ + 'blog-domain-mode' => 3, + 'open-register' => false, + ], +]; diff --git a/.gitignore b/.gitignore index 8264c45..563fc5c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ uoj_data_1/ uoj_data_2/ .php-cs-fixer.cache docker-compose.local.yml +.config.php diff --git a/docker-compose.development.yml b/docker-compose.development.yml index 90fb54b..37c4444 100644 --- a/docker-compose.development.yml +++ b/docker-compose.development.yml @@ -60,15 +60,6 @@ services: volumes: - ./uoj_data/web/data:/var/uoj_data - ./uoj_data/web/storage:/opt/uoj/web/app/storage + - ./.config.php:/opt/uoj/web/app/.config.php ports: - "80:80" - environment: - - UOJ_PROTOCOL=http - - DATABASE_HOST=uoj-db - - DATABASE_PASSWORD=root - - JUDGER_SOCKET_PORT=2333 - - JUDGER_SOCKET_PASSWORD=_judger_socket_password_ - - SALT_0=salt_0 - - SALT_1=salt_1 - - SALT_2=salt_2 - - SALT_3=salt_3 diff --git a/docker-compose.yml b/docker-compose.yml index f96fde1..1da0339 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -43,15 +43,6 @@ services: volumes: - ./uoj_data/web/data:/var/uoj_data - ./uoj_data/web/storage:/opt/uoj/web/app/storage + - ./.config.php:/opt/uoj/web/app/.config.php ports: - "80:80" - environment: - - UOJ_PROTOCOL=https - - DATABASE_HOST=uoj-db - - DATABASE_PASSWORD=root - - JUDGER_SOCKET_PORT=2333 - - JUDGER_SOCKET_PASSWORD=_judger_socket_password_ - - SALT_0=salt_0 - - SALT_1=salt_1 - - SALT_2=salt_2 - - SALT_3=salt_3 diff --git a/web/app/.default-config.php b/web/app/.default-config.php index dc84dbf..fab8e0e 100644 --- a/web/app/.default-config.php +++ b/web/app/.default-config.php @@ -20,21 +20,21 @@ return [ 'domain' => null, 'main' => [ 'protocol' => 'http', - 'host' => '_httpHost_', - 'port' => '80/443' + 'host' => UOJContext::requestDomain(), + 'port' => '80/443', ], 'blog' => [ 'protocol' => 'http', - 'host' => '_httpHost_', - 'port' => '80/443' + 'host' => UOJContext::requestDomain(), + 'port' => '80/443', ] ], 'security' => [ 'user' => [ - 'client_salt' => 'salt0' + 'client_salt' => 'salt0', ], 'cookie' => [ - 'checksum_salt' => ['salt1', 'salt2', 'salt3'] + 'checksum_salt' => ['salt1', 'salt2', 'salt3'], ], ], 'mail' => [ @@ -43,17 +43,17 @@ return [ 'password' => '_mail_noreply_password_', 'host' => 'smtp.local_uoj.ac', 'secure' => 'tls', - 'port' => 587 + 'port' => 587, ] ], 'judger' => [ 'socket' => [ 'port' => '233', - 'password' => '_judger_socket_password_' + 'password' => '_judger_socket_password_', ] ], 'switch' => [ 'blog-domain-mode' => 3, - 'open-register' => false - ] + 'open-register' => false, + ], ]; diff --git a/web/install.sh b/web/install.sh index f1996be..cc5b553 100644 --- a/web/install.sh +++ b/web/install.sh @@ -60,14 +60,6 @@ setWebConf(){ # Set webroot path ln -sf /opt/uoj/web /var/www/uoj chown -R www-data /var/www/uoj/app/storage - # Set web config file - php7.4 -a <include/uoj_work_path.h < 'http'/'protocol' => '$_uoj_protocol_'/g" /var/www/uoj/app/.config.php #Start services service ntp restart service apache2 restart From 4226b25e915c14302f7157663a8b3ebbc88cd434 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sun, 15 Jan 2023 19:59:17 +0800 Subject: [PATCH 27/30] fix: config --- .gitignore | 2 ++ docker-compose.development.yml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 563fc5c..e4d53e4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ uoj_data_2/ .php-cs-fixer.cache docker-compose.local.yml .config.php +.config.development.php +.config.local.php diff --git a/docker-compose.development.yml b/docker-compose.development.yml index 37c4444..31daa8d 100644 --- a/docker-compose.development.yml +++ b/docker-compose.development.yml @@ -60,6 +60,6 @@ services: volumes: - ./uoj_data/web/data:/var/uoj_data - ./uoj_data/web/storage:/opt/uoj/web/app/storage - - ./.config.php:/opt/uoj/web/app/.config.php + - ./.config.development.php:/opt/uoj/web/app/.config.php ports: - "80:80" From e43444e02df4099d6908b9d94e5ce3c58b829478 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sun, 15 Jan 2023 20:01:37 +0800 Subject: [PATCH 28/30] feat: reset_password --- web/app/controllers/forgot_pw.php | 154 +++++++++++++++++--------- web/app/controllers/reset_pw.php | 172 ++++++++++++++++-------------- 2 files changed, 199 insertions(+), 127 deletions(-) diff --git a/web/app/controllers/forgot_pw.php b/web/app/controllers/forgot_pw.php index c50d5d9..783e60b 100644 --- a/web/app/controllers/forgot_pw.php +++ b/web/app/controllers/forgot_pw.php @@ -1,59 +1,115 @@ addInput('username', 'text', '用户名', '', - function($username, &$vdata) { - if (!validateUsername($username)) { - return '用户名不合法'; - } - $vdata['user'] = UOJUser::query($username); - if (!$vdata['user']) { - return '该用户不存在'; - } - return ''; - }, - null - ); - $forgot_form->handle = function(&$vdata) { - $user = $vdata['user']; - $password = $user["password"]; - - $oj_name = UOJConfig::$data['profile']['oj-name']; - $oj_name_short = UOJConfig::$data['profile']['oj-name-short']; - $sufs = base64url_encode($user['username'] . "." . md5($user['username'] . "+" . $password)); - $url = HTML::url("/reset-password", array('params' => array('p' => $sufs))); - $html = <<addInput( + 'username', + 'text', + '用户名', + '', + function ($username, &$vdata) { + if (!validateUsername($username)) { + return '用户名不合法'; + } + $vdata['user'] = UOJUser::query($username); + if (!$vdata['user']) { + return '该用户不存在'; + } + return ''; + }, + null +); +$forgot_form->appendHTML(<< + +
        + +
        + +
        + +
        + +EOD); +$forgot_form->handle = function (&$vdata) { + $user = $vdata['user']; + $password = $user["password"]; + + if (!isset($_SESSION['phrase']) || !PhraseBuilder::comparePhrases($_SESSION['phrase'], $_POST['captcha'])) { + becomeMsgPage('验证码错误!'); + } + + if (!$user['email']) { + becomeMsgPage('用户未填写邮件地址,请联系管理员重置!'); + } + + $oj_name = UOJConfig::$data['profile']['oj-name']; + $oj_name_short = UOJConfig::$data['profile']['oj-name-short']; + $check_code = md5($user['username'] . "+" . $password . '+' . UOJTime::$time_now_str); + $sufs = base64url_encode($user['username'] . "." . $check_code); + $url = HTML::url("/reset-password", ['params' => ['p' => $sufs]]); + $oj_url = HTML::url('/'); + $name = $user['username']; + + if ($user['realname']) { + $name .= ' (' . $user['realname'] . ')'; + } + + $html = << -

        {$user['username']}您好,

        -

        您刚刚启用了{$oj_name_short}密码找回功能,请进入下面的链接重设您的密码:

        -

        $url

        -

        {$oj_name}

        +

        {$name} 您好,

        - +

        您最近告知我们需要重置您在 {$oj_name_short} 上账号的密码。请访问以下链接:{$url} (如果无法点击链接,请试着复制链接并粘贴至浏览器中打开。)

        +

        如果您没有请求重置密码,则忽略此信息。该链接将在 72 小时后自动过期失效。

        + +

        {$oj_name}

        +

        {$oj_url}

        EOD; - - $mailer = UOJMail::noreply(); - $mailer->addAddress($user['email'], $user['username']); - $mailer->Subject = $oj_name_short."密码找回"; - $mailer->msgHTML($html); - if (!$mailer->send()) { - error_log($mailer->ErrorInfo); - becomeMsgPage('

        邮件发送失败,请重试

        '); - } else { - becomeMsgPage('

        邮件发送成功

        '); - } - }; - $forgot_form->submit_button_config['align'] = 'offset'; - - $forgot_form->runAtServer(); - ?> + + $mailer = UOJMail::noreply(); + $mailer->addAddress($user['email'], $user['username']); + $mailer->Subject = $oj_name_short . " 密码找回"; + $mailer->msgHTML($html); + if (!$mailer->send()) { + error_log($mailer->ErrorInfo); + becomeMsgPage('

        邮件发送失败,请重试!

        '); + } else { + DB::update([ + "update user_info", + "set", [ + 'extra' => DB::json_set('extra', '$.reset_password_check_code', $check_code, '$.reset_password_time', UOJTime::$time_now_str), + ], + "where", [ + "username" => $user['username'], + ], + ]); + + becomeMsgPage('

        邮件发送成功,请检查收件箱!

        如果邮件未出现在收件箱中,请检查垃圾箱。
        '); + } +}; +$forgot_form->submit_button_config['align'] = 'offset'; + +$forgot_form->runAtServer(); +?>

        请输入需要找回密码的用户名:

        printHTML(); ?> + diff --git a/web/app/controllers/reset_pw.php b/web/app/controllers/reset_pw.php index 59080fe..0331f96 100644 --- a/web/app/controllers/reset_pw.php +++ b/web/app/controllers/reset_pw.php @@ -1,39 +1,55 @@ add(new DateInterval('P3D')) < UOJTime::$time_now) { + becomeMsgPage('链接已过期'); +} + +function resetPassword() { + global $user; + + if (!isset($_POST['newPW']) || !validatePassword($_POST['newPW'])) { + return '操作失败,无效密码'; } - function resetPassword() { - list($username, $check_code) = explode('.', base64url_decode($_GET['p'])); - if (!isset($_POST['newPW']) || !validatePassword($_POST['newPW'])) { - return '操作失败,无效密码'; - } - if (!isset($username) || !validateUsername($username)) { - return '不明错误'; - } - if (!isset($check_code)) { - return '不明错误'; - } - - $newPW = $_POST['newPW']; - $user = UOJUser::query($username); - if ($user == null) { - return '不明错误'; - } - if ($check_code !== md5($user['username'] . '+' . $user['password'])) { - return '不明错误'; - } - $newPW = getPasswordToStore($newPW, $user['username']); - DB::update("update user_info set password = '$newPW' where username = '{$user['username']}'"); - return 'ok'; - } - if (isset($_POST['reset'])) { - die(resetPassword()); - } - ?> + + $newPW = $_POST['newPW']; + $newPW = getPasswordToStore($newPW, $user['username']); + + DB::update([ + "update user_info", + "set", [ + "password" => $newPW, + "extra" => DB::json_remove('extra', '$.reset_password_check_code', '$.reset_password_time'), + ], + "where", [ + "username" => $user['username'], + ], + ]); + + return 'ok'; +} +if (isset($_POST['reset'])) { + die(resetPassword()); +} +?> +$REQUIRE_LIB['dialog'] = ''; +$REQUIRE_LIB['md5'] = ''; +?>
        @@ -44,60 +60,60 @@ - -
        -
        -
        -
        +
        +
        + +
        +
        From d410dff7d87acef26ad7347166da3aeab02fa376 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sun, 15 Jan 2023 20:15:52 +0800 Subject: [PATCH 29/30] feat(forgot_pw): add client info in email --- web/app/controllers/forgot_pw.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/web/app/controllers/forgot_pw.php b/web/app/controllers/forgot_pw.php index 783e60b..71fc4e4 100644 --- a/web/app/controllers/forgot_pw.php +++ b/web/app/controllers/forgot_pw.php @@ -52,6 +52,9 @@ $forgot_form->handle = function (&$vdata) { $url = HTML::url("/reset-password", ['params' => ['p' => $sufs]]); $oj_url = HTML::url('/'); $name = $user['username']; + $remote_addr = UOJContext::remoteAddr(); + $http_x_forwarded_for = UOJContext::httpXForwardedFor(); + $user_agent = UOJContext::httpUserAgent(); if ($user['realname']) { $name .= ' (' . $user['realname'] . ')'; @@ -65,6 +68,11 @@ $forgot_form->handle = function (&$vdata) {

        您最近告知我们需要重置您在 {$oj_name_short} 上账号的密码。请访问以下链接:{$url} (如果无法点击链接,请试着复制链接并粘贴至浏览器中打开。)

        如果您没有请求重置密码,则忽略此信息。该链接将在 72 小时后自动过期失效。

        +
          +
        • 请求 IP: {$remote_addr} (转发来源: {$http_x_forwarded_for})
        • +
        • 用户代理: {$user_agent}
        • +
        +

        {$oj_name}

        {$oj_url}

        EOD; From 6e5c15c925e484aeda592e5da8a98f93239a8da7 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Sun, 15 Jan 2023 20:47:54 +0800 Subject: [PATCH 30/30] feat(user): log http_x_forwarded_for in history --- web/app/models/UOJUser.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/app/models/UOJUser.php b/web/app/models/UOJUser.php index d86d1f3..29ba52f 100644 --- a/web/app/models/UOJUser.php +++ b/web/app/models/UOJUser.php @@ -382,6 +382,7 @@ class UOJUser { $extra = UOJUser::getExtra($user); $cur = [ 'addr' => $info['remote_addr'], + 'forwarded_addr' => $info['http_x_forwarded_for'], 'ua' => substr($info['http_user_agent'], 0, UOJUser::MAX_UA_LEN), 'last' => UOJTime::$time_now_str ];