diff options
author | Nguyễn Gia Phong <mcsinyx@disroot.org> | 2023-03-30 15:31:05 +0900 |
---|---|---|
committer | Nguyễn Gia Phong <mcsinyx@disroot.org> | 2023-03-30 15:31:05 +0900 |
commit | 26c8e08ede0bb12b98ed54ab45b1e39db595c271 (patch) | |
tree | 799a60603efdea04d1f59fc65cd6dfd78dbf1aa5 | |
parent | 1fec9d98a084106866d842d10f03dde9ff5472ee (diff) | |
download | rub-26c8e08ede0bb12b98ed54ab45b1e39db595c271.tar.gz |
Dogfood for documentation
-rw-r--r-- | doc/.gitignore | 3 | ||||
-rw-r--r-- | doc/base/karderio-Toy-baloon.svg | 161 | ||||
-rw-r--r-- | doc/base/pygments-dark.css | 83 | ||||
-rw-r--r-- | doc/base/pygments-light.css | 73 | ||||
-rw-r--r-- | doc/base/style.css | 173 | ||||
-rw-r--r-- | doc/html.xslt | 63 | ||||
-rw-r--r-- | doc/pages/demo/katex/index.xml | 115 | ||||
-rw-r--r-- | doc/pages/demo/pygments/index.xml | 66 | ||||
-rw-r--r-- | doc/pages/index.xml | 14 | ||||
-rw-r--r-- | doc/rss.xslt | 26 | ||||
-rwxr-xr-x | doc/rub | 95 | ||||
-rw-r--r-- | doc/shell.nix | 10 |
12 files changed, 882 insertions, 0 deletions
diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000..e2c5f1f --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,3 @@ +cache/ +out/ +.doit.db diff --git a/doc/base/karderio-Toy-baloon.svg b/doc/base/karderio-Toy-baloon.svg new file mode 100644 index 0000000..5fd9325 --- /dev/null +++ b/doc/base/karderio-Toy-baloon.svg @@ -0,0 +1,161 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns="http://www.w3.org/2000/svg" + xmlns:cc="http://web.resource.org/cc/" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:ns1="http://sozi.baierouge.fr" + xmlns:xlink="http://www.w3.org/1999/xlink" + id="svg2989" + sodipodi:docname="baloon.svg" + viewBox="0 0 422.04 468.44" + sodipodi:version="0.32" + version="1.0" + inkscape:version="0.44" + sodipodi:docbase="/home/ubun/Desktop" + > + <sodipodi:namedview + id="base" + bordercolor="#666666" + inkscape:pageshadow="2" + guidetolerance="10" + pagecolor="#ffffff" + gridtolerance="10000" + inkscape:window-height="598" + inkscape:zoom="0.35" + objecttolerance="10" + borderopacity="1.0" + inkscape:current-layer="layer1" + inkscape:cx="375" + inkscape:cy="520" + inkscape:window-y="51" + inkscape:window-x="0" + inkscape:window-width="946" + inkscape:pageopacity="0.0" + inkscape:document-units="px" + /> + <g + id="layer1" + inkscape:label="Layer 1" + inkscape:groupmode="layer" + transform="translate(-171.84 -272.42)" + > + <g + id="g1989" + style="stroke:black;stroke-width:2;fill:#ff7f2a" + transform="matrix(3.3799 0 0 3.2813 -1903.1 -2411.3)" + > + <path + id="path1991" + style="stroke:black;stroke-width:2;fill:#ff7f2a" + d="m653.39 946.79c-160.62-201.21 248.82-137.02 4.55 0.64-2.37 0.8-20.96 6.25-21.08 6.82-1.94 8.83 11.3 3.86 15.1 1.84-1.44 6.53 26.57 2.75 19.12-1.29-5.85-3.17-12.68-3.75-17.69-8.01z" + /> + </g + > + <g + id="g1997" + style="fill:white" + transform="matrix(3.3799 0 0 3.2813 -1903.1 -2411.3)" + > + <path + id="path1999" + style="fill:white" + d="m700.19 842.32c4.1-1.86 6.86-3.39 11.83-6.29 4.52 1.81 19.97 17.92 17.62 22.02-1.28 2.24-1.91 2.3-3.07 0.73-6.47-8.81-22.49-17.09-26.38-16.46z" + /> + </g + > + </g + > + <metadata + > + <rdf:RDF + > + <cc:Work + > + <dc:format + >image/svg+xml</dc:format + > + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" + /> + <cc:license + rdf:resource="http://creativecommons.org/licenses/publicdomain/" + /> + <dc:publisher + > + <cc:Agent + rdf:about="http://openclipart.org/" + > + <dc:title + >Openclipart</dc:title + > + </cc:Agent + > + </dc:publisher + > + <dc:title + >Toy baloon</dc:title + > + <dc:date + >2006-10-21T06:10:16</dc:date + > + <dc:description + >2D orange party baloon</dc:description + > + <dc:source + >https://openclipart.org/detail/808/toy-baloon-by-karderio</dc:source + > + <dc:creator + > + <cc:Agent + > + <dc:title + >karderio</dc:title + > + </cc:Agent + > + </dc:creator + > + <dc:subject + > + <rdf:Bag + > + <rdf:li + >line art</rdf:li + > + <rdf:li + >party baloon</rdf:li + > + <rdf:li + >toy baloon</rdf:li + > + </rdf:Bag + > + </dc:subject + > + </cc:Work + > + <cc:License + rdf:about="http://creativecommons.org/licenses/publicdomain/" + > + <cc:permits + rdf:resource="http://creativecommons.org/ns#Reproduction" + /> + <cc:permits + rdf:resource="http://creativecommons.org/ns#Distribution" + /> + <cc:permits + rdf:resource="http://creativecommons.org/ns#DerivativeWorks" + /> + </cc:License + > + </rdf:RDF + > + </metadata + > +</svg +> diff --git a/doc/base/pygments-dark.css b/doc/base/pygments-dark.css new file mode 100644 index 0000000..2160c0b --- /dev/null +++ b/doc/base/pygments-dark.css @@ -0,0 +1,83 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.hll { background-color: #0000ff } +.c { color: #00ff00 } /* Comment */ +.err { color: #dddddd } /* Error */ +.esc { color: #dddddd } /* Escape */ +.g { color: #dddddd } /* Generic */ +.k { color: #ff0000 } /* Keyword */ +.l { color: #dddddd } /* Literal */ +.n { color: #dddddd } /* Name */ +.o { color: #dddddd } /* Operator */ +.x { color: #dddddd } /* Other */ +.p { color: #dddddd } /* Punctuation */ +.ch { color: #00ff00 } /* Comment.Hashbang */ +.cm { color: #00ff00 } /* Comment.Multiline */ +.cp { color: #e5e5e5 } /* Comment.Preproc */ +.cpf { color: #00ff00 } /* Comment.PreprocFile */ +.c1 { color: #00ff00 } /* Comment.Single */ +.cs { color: #00ff00 } /* Comment.Special */ +.gd { color: #dddddd } /* Generic.Deleted */ +.ge { color: #dddddd } /* Generic.Emph */ +.gr { color: #dddddd } /* Generic.Error */ +.gh { color: #dddddd } /* Generic.Heading */ +.gi { color: #dddddd } /* Generic.Inserted */ +.go { color: #dddddd } /* Generic.Output */ +.gp { color: #dddddd } /* Generic.Prompt */ +.gs { color: #dddddd } /* Generic.Strong */ +.gu { color: #dddddd } /* Generic.Subheading */ +.gt { color: #dddddd } /* Generic.Traceback */ +.kc { color: #ff0000 } /* Keyword.Constant */ +.kd { color: #ff0000 } /* Keyword.Declaration */ +.kn { color: #ff0000 } /* Keyword.Namespace */ +.kp { color: #ff0000 } /* Keyword.Pseudo */ +.kr { color: #ff0000 } /* Keyword.Reserved */ +.kt { color: #ee82ee } /* Keyword.Type */ +.ld { color: #dddddd } /* Literal.Date */ +.m { color: #dddddd } /* Literal.Number */ +.s { color: #87ceeb } /* Literal.String */ +.na { color: #dddddd } /* Name.Attribute */ +.nb { color: #dddddd } /* Name.Builtin */ +.nc { color: #dddddd } /* Name.Class */ +.no { color: #7fffd4 } /* Name.Constant */ +.nd { color: #dddddd } /* Name.Decorator */ +.ni { color: #dddddd } /* Name.Entity */ +.ne { color: #dddddd } /* Name.Exception */ +.nf { color: #ffff00 } /* Name.Function */ +.nl { color: #dddddd } /* Name.Label */ +.nn { color: #dddddd } /* Name.Namespace */ +.nx { color: #dddddd } /* Name.Other */ +.py { color: #dddddd } /* Name.Property */ +.nt { color: #dddddd } /* Name.Tag */ +.nv { color: #eedd82 } /* Name.Variable */ +.ow { color: #dddddd } /* Operator.Word */ +.pm { color: #dddddd } /* Punctuation.Marker */ +.w { color: #dddddd } /* Text.Whitespace */ +.mb { color: #dddddd } /* Literal.Number.Bin */ +.mf { color: #dddddd } /* Literal.Number.Float */ +.mh { color: #dddddd } /* Literal.Number.Hex */ +.mi { color: #dddddd } /* Literal.Number.Integer */ +.mo { color: #dddddd } /* Literal.Number.Oct */ +.sa { color: #87ceeb } /* Literal.String.Affix */ +.sb { color: #87ceeb } /* Literal.String.Backtick */ +.sc { color: #87ceeb } /* Literal.String.Char */ +.dl { color: #87ceeb } /* Literal.String.Delimiter */ +.sd { color: #87ceeb } /* Literal.String.Doc */ +.s2 { color: #87ceeb } /* Literal.String.Double */ +.se { color: #87ceeb } /* Literal.String.Escape */ +.sh { color: #87ceeb } /* Literal.String.Heredoc */ +.si { color: #87ceeb } /* Literal.String.Interpol */ +.sx { color: #87ceeb } /* Literal.String.Other */ +.sr { color: #87ceeb } /* Literal.String.Regex */ +.s1 { color: #87ceeb } /* Literal.String.Single */ +.ss { color: #87ceeb } /* Literal.String.Symbol */ +.bp { color: #dddddd } /* Name.Builtin.Pseudo */ +.fm { color: #ffff00 } /* Name.Function.Magic */ +.vc { color: #eedd82 } /* Name.Variable.Class */ +.vg { color: #eedd82 } /* Name.Variable.Global */ +.vi { color: #eedd82 } /* Name.Variable.Instance */ +.vm { color: #eedd82 } /* Name.Variable.Magic */ +.il { color: #dddddd } /* Literal.Number.Integer.Long */ diff --git a/doc/base/pygments-light.css b/doc/base/pygments-light.css new file mode 100644 index 0000000..e2cc7b8 --- /dev/null +++ b/doc/base/pygments-light.css @@ -0,0 +1,73 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.hll { background-color: #ffffcc } +.c { color: #3D7B7B; font-style: italic } /* Comment */ +.err { border: 1px solid #FF0000 } /* Error */ +.k { color: #008000; font-weight: bold } /* Keyword */ +.o { color: #666666 } /* Operator */ +.ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ +.cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ +.cp { color: #9C6500 } /* Comment.Preproc */ +.cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ +.c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ +.cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ +.gd { color: #A00000 } /* Generic.Deleted */ +.ge { font-style: italic } /* Generic.Emph */ +.gr { color: #E40000 } /* Generic.Error */ +.gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.gi { color: #008400 } /* Generic.Inserted */ +.go { color: #717171 } /* Generic.Output */ +.gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.gs { font-weight: bold } /* Generic.Strong */ +.gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.gt { color: #0044DD } /* Generic.Traceback */ +.kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.kp { color: #008000 } /* Keyword.Pseudo */ +.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.kt { color: #B00040 } /* Keyword.Type */ +.m { color: #666666 } /* Literal.Number */ +.s { color: #BA2121 } /* Literal.String */ +.na { color: #687822 } /* Name.Attribute */ +.nb { color: #008000 } /* Name.Builtin */ +.nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.no { color: #880000 } /* Name.Constant */ +.nd { color: #AA22FF } /* Name.Decorator */ +.ni { color: #717171; font-weight: bold } /* Name.Entity */ +.ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ +.nf { color: #0000FF } /* Name.Function */ +.nl { color: #767600 } /* Name.Label */ +.nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.nt { color: #008000; font-weight: bold } /* Name.Tag */ +.nv { color: #19177C } /* Name.Variable */ +.ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.w { color: #bbbbbb } /* Text.Whitespace */ +.mb { color: #666666 } /* Literal.Number.Bin */ +.mf { color: #666666 } /* Literal.Number.Float */ +.mh { color: #666666 } /* Literal.Number.Hex */ +.mi { color: #666666 } /* Literal.Number.Integer */ +.mo { color: #666666 } /* Literal.Number.Oct */ +.sa { color: #BA2121 } /* Literal.String.Affix */ +.sb { color: #BA2121 } /* Literal.String.Backtick */ +.sc { color: #BA2121 } /* Literal.String.Char */ +.dl { color: #BA2121 } /* Literal.String.Delimiter */ +.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.s2 { color: #BA2121 } /* Literal.String.Double */ +.se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ +.sh { color: #BA2121 } /* Literal.String.Heredoc */ +.si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ +.sx { color: #008000 } /* Literal.String.Other */ +.sr { color: #A45A77 } /* Literal.String.Regex */ +.s1 { color: #BA2121 } /* Literal.String.Single */ +.ss { color: #19177C } /* Literal.String.Symbol */ +.bp { color: #008000 } /* Name.Builtin.Pseudo */ +.fm { color: #0000FF } /* Name.Function.Magic */ +.vc { color: #19177C } /* Name.Variable.Class */ +.vg { color: #19177C } /* Name.Variable.Global */ +.vi { color: #19177C } /* Name.Variable.Instance */ +.vm { color: #19177C } /* Name.Variable.Magic */ +.il { color: #666666 } /* Literal.Number.Integer.Long */ diff --git a/doc/base/style.css b/doc/base/style.css new file mode 100644 index 0000000..66349cb --- /dev/null +++ b/doc/base/style.css @@ -0,0 +1,173 @@ +@import "/pygments-light.css" (prefers-color-scheme: light); +@import "/pygments-dark.css" (prefers-color-scheme: dark); +:root { + --overlay-bg: #8881; + --overlay-border: #8884; +} + +/* Default font and layout */ +html { + box-sizing: border-box; + font-size: clamp(100%, 2vw, 150%); + margin: auto; + max-width: 36rem; +} + +body { margin: 0 1rem } + +/* Text geometry */ +p, details { + hyphens: auto; + text-align: justify; +} + +/* Headings */ +h2 a, h3 a, h4 a, h5 a, h6 a { color: CanvasText } + +.toc ol ol { + list-style-type: lower-alpha; +} + +/* General formatting */ +li p { margin: 0 } +a { text-decoration: none } +p a:hover { text-decoration: underline } + +sup.footnote-ref > a::before { content: '[' } +sup.footnote-ref > a::after { content: ']' } +section.footnotes { + font-size: 80%; + border: none; + margin: 1ex 0; +} +section.footnotes > ol { + counter-reset: list; + list-style-position: inside; + padding-left: 0; +} +section.footnotes > ol > li { counter-increment: list } +section.footnotes > ol > li::marker { + content: "[" counter(list, digit) "]\a0"; +} + +/* Images */ +figure { + margin: 0; + text-align: center; +} +img { + display: block; + margin: auto; + max-width: 100%; +} + +/* Boxes */ +blockquote, .note { + margin: 1ex -1rem; + padding-bottom: 1ex; + padding-left: 0.75rem; + padding-right: 1rem; + padding-top: 1ex; +} +blockquote p, .note p { margin: 1ex 0 } +.note p:first-child { font-weight: bold } +blockquote { + background: var(--overlay-bg); + border-left: 0.25rem solid var(--overlay-border); +} +.note { + background-color: #2482; + border-left: 0.25rem solid #2484; +} + +/* Header */ +header { + margin: 1.5rem -0.5rem; + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; +} + +header a { + border-bottom: solid; + font-weight: bold; + margin: 0 0.5rem; + text-decoration: none; +} + +nav, nav li { display: inline-block } +nav ul { margin: 0 } + +footer, .tags, .right { + color: GrayText; + font-size: 80%; +} + +footer { + margin-top: 1.5rem; + margin-bottom: 2rem; +} + +footer a, .tags a { + color: GrayText; + text-decoration: underline; +} + +.nowrap { display: inline-block } +.tags { float: left } +.right { + float: right; + margin-left: auto; +} + +/* Table */ +table { + border-bottom: 0.15em solid; + border-collapse: collapse; + border-top: 0.15em solid; + line-height: 1em; + margin-bottom: 1.5em; + margin-left: auto; + margin-right: auto; + text-align: center; +} + +tr:first-of-type > th { border-bottom: 0.08em solid } +tr, th, td { padding: 0.5em } + +/* highlight.js */ +code, .highlight { background-color: var(--overlay-bg) } +.highlight { + display: block; + padding: 0 1ch; + margin: 0 -1ch; + overflow-x: auto; +} +.highlight > pre { margin: 1ex 0 } +pre p { margin: 0 } + +.comment { + background-color: var(--overlay-bg); + clear: both; + margin: 1ex 0; + overflow: hidden; + padding: 0 1rem; +} + +.fead { + display: flex; + flex-wrap: wrap; + margin: -0.5rem; + margin-bottom: 0; +} +.fead h3 { margin: 0 0 1ex } +.fead article { + background: var(--overlay-bg); + display: flex; + flex-direction: column; + flex: 1 1 0; + margin: 1ex; + min-width: 12rem; + padding: 1ex; +} diff --git a/doc/html.xslt b/doc/html.xslt new file mode 100644 index 0000000..5ad48ad --- /dev/null +++ b/doc/html.xslt @@ -0,0 +1,63 @@ +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:rub="https://rub.parody" extension-element-prefixes="rub"> + <xsl:output method="xml" indent="yes" encoding="UTF-8"/> + <xsl:template match="*"><rub:eval/></xsl:template> + + <xsl:template match="/rub:page"> + <html lang="en"> + <head> + <meta charset="utf-8"/> + <meta name="color-scheme" content="dark light"/> + <meta name="viewport" content="width=device-width,initial-scale=1.0"/> + <xsl:if test="rub:description != ''"> + <meta name="description" content="{rub:description}"/> + </xsl:if> + <link rel="alternate" type="application/atom+xml" href="/index.xml"/> + <link rel="icon" href="/karderio-Toy-baloon.svg"/> + <link rel="stylesheet" href="/style.css"/> + <title><xsl:value-of select="rub:title"/></title> + </head> + <body> + <header> + <div class="blog-name"><a href="/">Rub</a></div> + <nav> + <ul> + <li><a href="/demo">Demoes</a></li> + </ul> + </nav> + </header> + <main> + <h1><xsl:value-of select="rub:title"/></h1> + <xsl:apply-templates select="rub:markdown"/> + </main> + <xsl:if test="boolean(rub:category)"> + <small class="tags"> + <strong>Tags:</strong> + <xsl:for-each select="rub:category"> + <xsl:text> </xsl:text> + <a href="/tag/{.}"><xsl:value-of select="."/></a> + </xsl:for-each> + </small> + <br/> + </xsl:if> + <footer> + Copyright and stuff + </footer> + </body> + </html> + </xsl:template> + + <xsl:template match="h2|h3|h4|h5|h6"> + <xsl:element name="{name()}"> + <xsl:attribute name="id"> + <xsl:value-of select="text()"/> + </xsl:attribute> + <a href="#{text()}"><xsl:value-of select="."/></a> + </xsl:element> + </xsl:template> + + <!-- Remove paragraph inside footnote list item --> + <xsl:template match="li[starts-with(@id, 'fn-')]/p"> + <xsl:copy-of select='@*|node()'/> + </xsl:template> +</xsl:stylesheet> diff --git a/doc/pages/demo/katex/index.xml b/doc/pages/demo/katex/index.xml new file mode 100644 index 0000000..e7ecb02 --- /dev/null +++ b/doc/pages/demo/katex/index.xml @@ -0,0 +1,115 @@ +<page xmlns="https://rub.parody"> +<title>KaTeX demo</title> +<description>Math formulae to demo LaTeX to MathML rendering</description> +<date>2020-04-15</date> +<category>demo</category> +<category>math</category> +<markdown> +Given two discrete-time systems <m>A</m> and <m>B</m> connected in cascade +to form a new system <m>C = x \mapsto B(A(x))</m>, we examine +the following properties: + +## Linearity + +If <m>A</m> and <m>B</m> are linear, +i.e. for all signals <m>x_i</m> and scalars <m>a_i</m>, + +<math> +\begin{aligned} + A\left(n \mapsto \sum_i a_i x_i[n]\right) = n \mapsto \sum_i a_i A(x_i)[n]\\ + B\left(n \mapsto \sum_i a_i x_i[n]\right) = n \mapsto \sum_i a_i B(x_i)[n] +\end{aligned} +</math> + +then <m>C</m> is also linear + +<math><![CDATA[ +\begin{aligned} + C\left(n \mapsto \sum_i a_i x_i[n]\right) + &= B\left(A\left(n \mapsto \sum_i a_i x_i[n]\right)\right)\\ + &= B\left(n \mapsto \sum_i a_i A(x_i)[n]\right)\\ + &= n \mapsto \sum_i a_i B(A(x_i))[n]\\ + &= n \mapsto \sum_i a_i C(x_i)[n] +\end{aligned} +]]></math> + +## Time Invariance + +If <m>A</m> and <m>B</m> are time invariant, +i.e. for all signals <m>x</m> and integers <m>k</m>, + +<math><![CDATA[ +\begin{aligned} + A(n \mapsto x[n - k]) &= n \mapsto A(x)[n - k]\\ + B(n \mapsto x[n - k]) &= n \mapsto B(x)[n - k] +\end{aligned} +]]></math> + +then <m>C</m> is also time invariant + +<math><![CDATA[ +\begin{aligned} + C(n \mapsto x[n - k]) + &= B(A(n \mapsto x[n - k]))\\ + &= B(n \mapsto A(x)[n - k])\\ + &= n \mapsto B(A(x))[n - k]\\ + &= n \mapsto C(x)[n - k] +\end{aligned} +]]></math> + +## LTI Ordering + +If <m>A</m> and <m>B</m> are linear and time-invariant, there exists +signals <m>g</m> and <m>h</m> such that for all signals <m>x</m>, +<m>A = x \mapsto x * g</m> and <m>B = x \mapsto x * h</m>, thus + +<math> +B(A(x)) = B(x * g) = x * g * h = x * h * g = A(x * h) = A(B(x)) +</math> + +or interchanging <m>A</m> and <m>B</m> order does not change <m>C</m>. + +## Causality + +If <m>A</m> and <m>B</m> are causal, +i.e. for all signals <m>x</m>, <m>y</m> and any choise of integer <m>k</m>, + +<math><![CDATA[ +\begin{aligned} + \forall n < k, x[n] = y[n]\quad + \Longrightarrow &\;\begin{cases} + \forall n < k, A(x)[n] = A(y)[n]\\ + \forall n < k, B(x)[n] = B(y)[n] + \end{cases}\\ + \Longrightarrow &\;\forall n < k, B(A(x))[n] = B(A(y))[n]\\ + \Longleftrightarrow &\;\forall n < k, C(x)[n] = C(y)[n] +\end{aligned} +]]></math> + +then <m>C</m> is also causal. + +## BIBO Stability + +If <m>A</m> and <m>B</m> are stable, i.e. there exists a signal <m>x</m> +and scalars <m>a</m> and <m>b</m> that for all integers <m>n</m>, + +<math><![CDATA[ +\begin{aligned} + |x[n]| < a &\Longrightarrow |A(x)[n]| < b\\ + |x[n]| < a &\Longrightarrow |B(x)[n]| < b +\end{aligned} +]]></math> + +then <m>C</m> is also stable, i.e. there exists a signal <m>x</m> +and scalars <m>a</m>, <m>b</m> and <m>c</m> that for all integers <m>n</m>, + +<math><![CDATA[ +\begin{aligned} + |x[n]| < a\quad + \Longrightarrow &\;|A(x)[n]| < b\\ + \Longrightarrow &\;|B(A(x))[n]| < c\\ + \Longleftrightarrow &\;|C(x)[n]| < c +\end{aligned} +]]></math> +</markdown> +</page> diff --git a/doc/pages/demo/pygments/index.xml b/doc/pages/demo/pygments/index.xml new file mode 100644 index 0000000..361c6ab --- /dev/null +++ b/doc/pages/demo/pygments/index.xml @@ -0,0 +1,66 @@ +<page xmlns="https://rub.parody"> +<title>Pygments demo</title> +<description>Code snippets to demonstrate syntax highlighting</description> +<date>2022-12-26</date> +<category>demo</category> +<category>aoc</category> +<markdown> +Syntax highlighting for D using Pygments: + +<highlight lang="d"><![CDATA[ +import core.stdc.stdio : getchar, printf; + +extern(C) void main() +{ + slide: for (auto q = 0u, i = 1u; q & 0xffu ^ '\n'; ++i) + { + q <<= 8u; + q |= getchar(); + if (i < 4) + continue; + + auto p = cast(ubyte*) &q; + for (auto s = 0u, j = 0u; j < 4u; ++j) + { + auto b = 1u << (p[j] & 0x1fu); + if (s & b) + continue slide; + s |= b; + } + + printf("%d\n", i); + break; + } +} +]]></highlight> + +The same but let Pygments guess the language: + +<highlight><![CDATA[ +import core.stdc.stdio : getchar, printf; + +extern(C) void main() +{ + slide: for (auto q = 0u, i = 1u; q & 0xffu ^ '\n'; ++i) + { + q <<= 8u; + q |= getchar(); + if (i < 4) + continue; + + auto p = cast(ubyte*) &q; + for (auto s = 0u, j = 0u; j < 4u; ++j) + { + auto b = 1u << (p[j] & 0x1fu); + if (s & b) + continue slide; + s |= b; + } + + printf("%d\n", i); + break; + } +} +]]></highlight> +</markdown> +</page> diff --git a/doc/pages/index.xml b/doc/pages/index.xml new file mode 100644 index 0000000..1a77965 --- /dev/null +++ b/doc/pages/index.xml @@ -0,0 +1,14 @@ +<page xmlns="https://rub.parody"> +<title>Rub</title> +<markdown> +Rub is a static generator framework. + +## Demoes + +* [MathML rendering](/demo/katex) via [KaTeX] +* [Syntax highlighting](/demo/pygments) via [Pygments] + +[KaTeX]: https://katex.org +[Pygments]: https://pygments.org +</markdown> +</page> diff --git a/doc/rss.xslt b/doc/rss.xslt new file mode 100644 index 0000000..48f9203 --- /dev/null +++ b/doc/rss.xslt @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:rub="https://rub.parody" extension-element-prefixes="rub" + xmlns:content="http://purl.org/rss/1.0/modules/content/"> + <xsl:template match="/feed"> + <rss version="2.0"> + <channel> + <title>Demo RSS feed</title> + <link>https://rub.parody/</link> + <description>Global feed</description> + <generator>Rub</generator> + <xsl:for-each select="entry"> + <item> + <title><xsl:value-of select="title"/></title> + <description><xsl:value-of select="description"/></description> + <content:encoded> + <xsl:apply-templates select="html/body/main"/> + </content:encoded> + </item> + </xsl:for-each> + </channel> + </rss> + </xsl:template> + + <xsl:template match="main"><rub:serialize/></xsl:template> +</xsl:stylesheet> diff --git a/doc/rub b/doc/rub new file mode 100755 index 0000000..d1113a2 --- /dev/null +++ b/doc/rub @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +from contextlib import contextmanager +from functools import partial +from pathlib import Path +from shutil import which +from subprocess import PIPE, Popen +from urllib.request import Request, urlopen +from xml.sax.saxutils import unescape + +from lxml.etree import Element, XML +from lxml.html import (fragment_fromstring as from_html_fragment, + fragments_fromstring as from_html_fragments) +from mistune import html as from_md +from pygments import highlight +from pygments.formatters import HtmlFormatter +from pygments.lexers import get_lexer_by_name, guess_lexer +from rub import rub, xml + +PYGMENTS_FORMATTER = HtmlFormatter(lineseparator='<br/>') +KATEX_SERVER = ''' +var http = require('http'); +var katex = require('katex'); + +let server = http.createServer((request, response) => { + if (request.method === 'POST') { + response.writeHead(200, 'OK'); + var body = ''; + request.on('data', (chunk) => body += chunk); + request.on('end', () => { + response.write(katex.renderToString(body, { + displayMode: request.headers['x-katex-mode'] === 'display', + output: 'mathml', + })); + response.end(); + }); + } else { + response.writeHead(405, 'Method Not Allowed'); + response.end(); + } +}); +server.listen(() => { + console.log('http://localhost:' + server.address().port); +}); +''' + + +def mistune(extension, context, input_node, output_parent): + """Render Markdown to HTML.""" + tmp = Element('tmp') + xml.recurse(extension, context, input_node, tmp) + tmp[0].text = input_node.text + text = xml.serialize_content(tmp[0]).decode() + for i in from_html_fragments(from_md(unescape(text))): + extension.apply_templates(context, i, output_parent) + + +def pygments(extension, context, input_node, output_parent): + """Highlight code syntax in HTML.""" + code = input_node.text + lang = input_node.get('lang') + lexer = guess_lexer(code) if lang is None else get_lexer_by_name(lang) + output = from_html_fragment(highlight(code, lexer, PYGMENTS_FORMATTER)) + output.tail = input_node.tail + output_parent.append(output) + + +def katex(extension, context, input_node, output_parent, url, display=False): + """Render LaTeX to content MathML.""" + with urlopen(Request(url, xml.serialize_content(input_node), + {'X-KaTeX-Mode': 'display'} if display else {})) as r: + output = XML(r.read())[0] # remove span[@class='katex'] + output.tail = input_node.tail + output_parent.append(output) + + +@contextmanager +def katex_server(): + server = Popen(which('node'), stdin=PIPE, stdout=PIPE, text=True) + try: + server.stdin.write(KATEX_SERVER) + server.stdin.close() + yield partial(katex, url=server.stdout.readline().strip()) + finally: + server.kill() + + +with katex_server() as mathml: + wd = Path(__file__).parent + rub(xml.Processor(wd/'html.xslt', + partial(Path.with_suffix, suffix='.html'), + markdown=mistune, highlight=pygments, + math=partial(mathml, display=True), m=mathml), + xml.Processor(wd/'rss.xslt', + partial(Path.with_name, name='index.xml')), + wd/'base', wd/'pages', wd/'cache', wd/'out') diff --git a/doc/shell.nix b/doc/shell.nix new file mode 100644 index 0000000..453398c --- /dev/null +++ b/doc/shell.nix @@ -0,0 +1,10 @@ +with import <nixpkgs> {}; +mkShell { + packages = (with python3Packages; [ + doit lxml mistune pygments + ]) ++ [ nodejs nodePackages.katex ]; + + shellHook = '' + PYTHONPATH=../src:$PYTHONPATH + ''; +} |