903 lines
140 KiB
XML
903 lines
140 KiB
XML
<?xml version='1.0' encoding='UTF-8'?>
|
||
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"><id>https://alex.vxcc.dev</id><title>alex168's blog</title><updated>2025-08-29T13:46:41.354526+00:00</updated><author><name>Alexander Nutz</name><email>nutz.alexander@vxcc.dev</email><uri>https://alex.vxcc.dev</uri></author><link href="https://alex.vxcc.dev/atom.xml" rel="self"/><link href="https://alex.vxcc.dev/" rel="alternate"/><generator uri="https://lkiesow.github.io/python-feedgen" version="1.0.0">python-feedgen</generator><icon>https://vxcc.dev/alex/res/favicon.png</icon><subtitle>alex_s168's blog</subtitle><entry><id>https://vxcc.dev/alex/compiler-inlining.typ.desktop.html</id><title>Automatically inlining functions is not easy</title><updated>2025-08-11T16:38:10+02:00</updated><author><name>Alexander Nutz</name><email>nutz.alexander@vxcc.dev</email><uri>https://alex.vxcc.dev</uri></author><content type="html"><!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<title>Automatically inlining functions is not easy</title>
|
||
<meta charset="utf-8">
|
||
</head>
|
||
<body>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h1>Automatically inlining functions is not easy</h1>
|
||
<p><span style="font-size: 9pt"><p>Last modified: 11. August 2025 16:38 (Git #<code><code style="white-space: pre-wrap">9c2913af</code></code>)</p><p>Written by <a href="https://alex.vxcc.dev">alex_s168</a></p></span></p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Introduction</h2>
|
||
<p>Function calls have some overhead, which can sometimes be a big issue for other optimizations. Because of that, compiler backends (should) inline function calls. There are however many issues with just greedily inlining calls…</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Greedy inlining with heuristics</h2>
|
||
<p>This is the most obvious approach. We can just inline all functions with only one call, and then inline calls where the inlined function does not have many instructions.</p>
|
||
<p>Example:</p>
|
||
<p><code><pre><code>function f32 $square(f32 %x) {<br>@entry:<br> // this is stupid, but I couldn't come up with a better example<br> f32 %e = add %x, 0<br> f32 %out = add %e, %x<br> ret %out<br>}<br><br>function f32 $hypot(f32 %a, f32 %b) {<br>@entry:<br> f32 %as = call $square(%a)<br> f32 %bs = call $square(%b)<br> f32 %sum = add %as, %bs<br> f32 %o = sqrt %sum<br> ret %o<br>}<br><br>function f32 $tri_hypot({f32, f32} %x) {<br> f32 %a = extract %x, 0<br> f32 %b = extract %x, 1<br> f32 %o = call $hypot(%a, %b) // this is a "tail call"<br> ret %o<br>}<br><br>// let's assume that $hypot is used someplace else in the code too</code></pre></code></p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
"><br>Let’s assume our inlining treshold is 5 operations. Then we would get – Waait there are multiple options…</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Issue 1: (sometimes) multiple options</h3>
|
||
<p>If we inline the <code><code style="white-space: pre-wrap">$square</code></code> calls, then <code><code style="white-space: pre-wrap">$hypot</code></code> will have too many instructions to be inlined into <code><code style="white-space: pre-wrap">$tri_hypot</code></code>:</p>
|
||
<p><code><pre><code>...<br>function f32 $hypot(f32 %a, f32 %b) {<br>@entry:<br> // more instructions than our inlining treshold:<br> f32 %ase = add %a, 0<br> f32 %as = add %ase, %a<br> f32 %bse = add %b, 0<br> f32 %bs = add %bse, %b<br> f32 %sum = add %as, %bs<br> f32 %o = sqrt %sum<br> ret %o<br>}<br>...</code></pre></code></p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br>The second option is to inline the <code><code style="white-space: pre-wrap">$hypot</code></code> call into <code><code style="white-space: pre-wrap">$tri_hypot</code></code>. (There are also some other options)</p>
|
||
<p>Now in this case, it seems obvious to prefer inlining <code><code style="white-space: pre-wrap">$square</code></code> into <code><code style="white-space: pre-wrap">$hypot</code></code>.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Issue 2: ABI requirements on argument passing</h3>
|
||
<p>If we assume the target ABI only has one f32 register for passing arguments, then we would have to generate additional instructions for passing the second argument of <code><code style="white-space: pre-wrap">$hypot</code></code>, and then it might actually be more efficient to inline <code><code style="white-space: pre-wrap">$hypot</code></code> instead of <code><code style="white-space: pre-wrap">$square</code></code>.</p>
|
||
<p>This example is not realistic, but this issue actually occurs when compiling lots of code.</p>
|
||
<p>Another related issue is that having more arguments arranged in a fixed way will require lots of moving data arround at the call site.</p>
|
||
<p>A solution to this is to make the heuristics not just output code size, but also make it depend on the number of arguments / outputs passed to the function.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Issue 3: (sometimes) prevents optimizations</h3>
|
||
<p><code><pre><code>function f32 $myfunc(f32 %a, f32 %b) {<br>@entry:<br> f32 %sum = add %a, %b<br> f32 %sq = sqrt %sum<br> ...<br>}<br><br>function $callsite(f32 %a, f32 %b) {<br>@entry:<br> f32 %as = add %a, %a<br> f32 %bs = add %b, %b<br> f32 %x = call $myfunc(%as, %bs)<br> ...<br>}</code></pre></code></p>
|
||
<p>If the target has a efficient <code><code style="white-space: pre-wrap">hypot</code></code> operation, then that operation will only be used if we inline <code><code style="white-space: pre-wrap">$myfunc</code></code> into <code><code style="white-space: pre-wrap">$callsite</code></code>.</p>
|
||
<p>This means that inlining is now depended on… instruction selection??</p>
|
||
<p>This is not the only optimization prevented by not inlining the call. If <code><code style="white-space: pre-wrap">$callsite</code></code> were to be called in a loop, then not inlining would prevent vectorization.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Function outlining</h2>
|
||
<p>A related optimization is “outlining”. It’s the opposite to inlining. It moves duplicate code into a function, to reduce code size, and sometimes increase performance (because of instruction caching)</p>
|
||
<p>If we do inlining seperately from outlining, we often get unoptimal code.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>A better approach</h2>
|
||
<p>We can instead first inline <strong>all</strong> inlinable calls, and <strong>then</strong> perform more agressive outlining.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Step 1: inlining</h3>
|
||
<p>We inline <strong>all</strong> function calls, except for:</p>
|
||
<ul>
|
||
<li>self recursion (obviously)</li>
|
||
<li>functions explicitly marked as no-inline by the user</li>
|
||
</ul>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Step 2: detect duplicate code</h3>
|
||
<p>There are many algorithms for doing this.</p>
|
||
<p>The goal of this step is to both:</p>
|
||
<ul>
|
||
<li>maximize size of outlinable section</li>
|
||
<li>minimize size of code</li>
|
||
</ul>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Step 3: slightly reduce size of outlinable section</h3>
|
||
<p>The goal is to reduce size of outlinable sections, to make the code more optimal.</p>
|
||
<p>This should be ABI and instruction depended, and have the goal of:</p>
|
||
<ul>
|
||
<li>reducing argument shuffles required at all call sites</li>
|
||
<li>reducing register preassure</li>
|
||
<li>not preventing good isel choices and optimizations.</li>
|
||
</ul>
|
||
<p>this is also dependent on the targetted code size.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Step 4: perform outlining</h3>
|
||
<p>This is obvious.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Issue 1: high compile-time memory usage</h3>
|
||
<p>Inlining <strong>all</strong> function calls first will increase the memory usage during compilation by A LOT</p>
|
||
<p>I’m sure that there is a smarter way to implement this method, without actually performing the inlining…</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Conclusion</h2>
|
||
<p>Function inlining is much more complex than one might think.</p>
|
||
<p>PS: No idea how to implement this…</p>
|
||
<p>Subscribe to the <a href="atom.xml">Atom feed</a> to get notified about futre compiler-related articles.</p>
|
||
</div>
|
||
</body>
|
||
</html>
|
||
</content><link href="compiler-inlining.typ.desktop.html"/><summary>Compiler backends should automatically inline functions, to get rid to avoid function call overhead. A greedy approach has many issues. We'll be exploring a better approach.</summary></entry><entry><id>https://vxcc.dev/alex/compiler-pattern-matching.typ.desktop.html</id><title>Approaches to pattern matching in compilers</title><updated>2025-08-19T09:55:17+02:00</updated><author><name>Alexander Nutz</name><email>nutz.alexander@vxcc.dev</email><uri>https://alex.vxcc.dev</uri></author><content type="html"><!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<title>Approaches to Compiler Pattern Matching</title>
|
||
<meta charset="utf-8">
|
||
</head>
|
||
<body>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h1>Approaches to pattern matching in compilers</h1>
|
||
<p><span style="font-size: 9pt"><p>Last modified: 19. August 2025 09:55 (Git #<code><code style="white-space: pre-wrap">34fd6adb</code></code>)</p><p>Written by <a href="https://alex.vxcc.dev">alex_s168</a></p></span></p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Introduction</h2>
|
||
<p>Compilers often have to deal with pattern matching and rewriting (find-and-replace) inside the compiler IR (intermediate representation).</p>
|
||
<p>Common use cases for pattern matching in compilers:</p>
|
||
<ul>
|
||
<li>“peephole optimizations”: the most common kind of optimization in compilers. They find a short sequence of code and replace it with some other code. For example replacing <code><code style="white-space: pre-wrap">x <span style="color: #d73a49">&amp;</span> (<span style="color: #b60157">1</span> <span style="color: #d73a49">&lt;&lt;</span> b)</code></code> with a bit test operation.</li>
|
||
<li>finding a sequence of operations for complex optimization passes to operate on: advanced compilers have complex optimizations that can’t really be performed with simple IR operation replacements, and instead require complex logic. Patterns are used here to find operation sequences where those optimizations are applicable, and also to extract details inside that sequence.</li>
|
||
<li>code generation: converting the IR to machine code / VM bytecode. A compiler needs to find operations (or sequences of operations) inside the IR, and “replace” them with machine code.</li>
|
||
</ul>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Simplest Approach</h2>
|
||
<p>Currently, most compilers mostly do this inside their source code. For example, in MLIR, most (but not all) pattern matches are performed in C++ code.</p>
|
||
<p>The only advantage to this approach is that it doesn’t require a complex pattern matching system.</p>
|
||
<p>I only recommend doing this for small compiler toy projects.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Disadvantages</h3>
|
||
<p>Doing pattern matching this way has many disadvantages.</p>
|
||
<p><br>Some (but not all):</p>
|
||
<ul>
|
||
<li>debugging pattern match rules can be hard</li>
|
||
<li>IR rewrites need to be tracked manually (for debugging)</li>
|
||
<li>source locations and debug information also need to be tracked manually, which often isn’t implemented very well.</li>
|
||
<li>verbose and barely readable pattern matching code</li>
|
||
<li>overall error-prone</li>
|
||
</ul>
|
||
<p>I myself did pattern matching this way in my old compiler backend, and I speak from experience when I say that this approach <strong>sucks</strong> (in most cases).</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Pattern Matching DSLs</h2>
|
||
<p>A custom language for describing IR patterns and IR transformations (aka rewrites).</p>
|
||
<p>I will put this into the category of “structured pattern matching”.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br>An example is Cranelift’s ISLE DSL:</p>
|
||
<p><code><pre><code><span style="color: #8a8a8a">;;</span><span style="color: #8a8a8a"> x ^ x == 0.</span><br>(<span style="color: #4b69c6">rule</span> (<span style="color: #4b69c6">simplify</span> (<span style="color: #4b69c6">bxor</span> (<span style="color: #4b69c6">ty_int</span> ty) x x))<br> (<span style="color: #4b69c6">subsume</span> (<span style="color: #4b69c6">iconst_u</span> ty <span style="color: #b60157">0</span>)))</code></pre></code></p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br>Another example is tinygrad’s pattern system:</p>
|
||
<p><code><pre><code>(<span style="color: #4b69c6">UPat</span>(Ops.AND, src<span style="color: #d73a49">=</span>(<br> UPat.<span style="color: #4b69c6">var</span>(<span style="color: #298e0d">"</span><span style="color: #298e0d">x</span><span style="color: #298e0d">"</span>),<br> <span style="color: #4b69c6">UPat</span>(Ops.SHL, src<span style="color: #d73a49">=</span>(<br> UPat.<span style="color: #4b69c6">const</span>(<span style="color: #b60157">1</span>),<br> UPat.<span style="color: #4b69c6">var</span>(<span style="color: #298e0d">"</span><span style="color: #298e0d">b</span><span style="color: #298e0d">"</span>)))),<br> <span style="color: #d73a49">lambda</span> x,b: <span style="color: #4b69c6">UOp</span>(Ops.BIT_TEST, src<span style="color: #d73a49">=</span>(x, b)))</code></pre></code></p>
|
||
<p>Fun fact: tinygrad actually decompiles the python code inside the second element of the pair, and runs multiple optimization passes on that.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
"><br>This approach is used by many popular compilers such as LLVM, GCC, and Cranelift for peephole optimizations and code generation.</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Advantages</h3>
|
||
<ul>
|
||
<li><strong>debugging and tracking of rewrites, source locations, and debug information can be done properly</strong></li>
|
||
<li>patterns themselves can be inspected and modified programmatically.</li>
|
||
<li>they are easier to use and read than manual pattern matching in the source code.</li>
|
||
</ul>
|
||
<p><br>There is however an even better alternative:</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Pattern Matching Dialects</h2>
|
||
<p>I will also put this method into the category of “structured pattern matching”.</p>
|
||
<p><br>The main example of this is MLIR, with the <code><code style="white-space: pre-wrap">pdl</code></code> and the <code><code style="white-space: pre-wrap">transform</code></code> dialects. Sadly few projects/people use these dialects, and instead do pattern matching in C++ code. Probably because the dialects aren’t documented very well.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>What are compiler dialects?</h3>
|
||
<p>Modern compilers, especially multi-level compilers, such as MLIR, have their operations grouped in “dialects”.</p>
|
||
<p>Each dialect either represents specific kinds of operations, like arithmetic operations, or a specific backend’s/frontend’s operations, such as the <code><code style="white-space: pre-wrap">llvm</code></code>, <code><code style="white-space: pre-wrap">emitc</code></code>, and the <code><code style="white-space: pre-wrap">spirv</code></code> dialects in MLIR.</p>
|
||
<p>Dialects commonly contain operations, data types, as well as optimization and dialect conversion passes.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Core Concept</h3>
|
||
<p>The IR patterns and transformations are represented using the compiler’s IR. This is mostly done in a separate dialect, with dedicated operations for operating on IR.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Examples</h3>
|
||
<p>MLIR’s <code><code style="white-space: pre-wrap">pdl</code></code> dialect can be used to replace <code><code style="white-space: pre-wrap">arith.addi</code></code> with <code><code style="white-space: pre-wrap">my.add</code></code> like this:</p>
|
||
<p><code><pre><code>pdl.pattern <span style="color: #d73a49">@replace_addi_with_my_add</span> : benefit(<span style="color: #b60157">1</span>) {<br> <span style="color: #d73a49">%arg0</span> = pdl.operand<br> <span style="color: #d73a49">%arg1</span> = pdl.operand<br> <span style="color: #d73a49">%op</span> = pdl.operation <span style="color: #298e0d">"arith.addi"</span>(<span style="color: #d73a49">%arg0</span>, <span style="color: #d73a49">%arg1</span>)<br><br> pdl.rewrite <span style="color: #d73a49">%op</span> {<br> <span style="color: #d73a49">%new_op</span> = pdl.operation <span style="color: #298e0d">"my.add"</span>(<span style="color: #d73a49">%arg0</span>, <span style="color: #d73a49">%arg1</span>) -> (<span style="color: #d73a49">%op</span>)<br> pdl.replace <span style="color: #d73a49">%op</span> with <span style="color: #d73a49">%new_op</span><br> }<br>}</code></pre></code></p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Advantages</h3>
|
||
<ul>
|
||
<li>the pattern matching infrastructure can optimize it’s own patterns: The compiler can operate on patterns and rewrite rules like they are normal operations. This removes the need for special infrastructure regarding pattern matching DSLs.</li>
|
||
<li>the compiler could AOT compile patterns</li>
|
||
<li>the compiler could optimize, analyze, and combine patterns to reduce compile time.</li>
|
||
<li>IR (de-)serialization infrastructure in the compiler can also be used to exchange peephole optimizations.</li>
|
||
<li>bragging rights: your compiler represents its patterns in it’s own IR</li>
|
||
</ul>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Combining with a DSL</h3>
|
||
<p>I recommend having a pattern matching / rewrite DSL, that transpiles to pattern matching / rewrite dialect operations.</p>
|
||
<p>The advantage of this over just having a rewrite dialect is that it makes patterns even more readable (and maintainable!)</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>E-Graphs</h3>
|
||
<p><span class style="white-space:nowrap;"><a href="https://en.wikipedia.org/wiki/E-graph">E-Graphs</a></span> are magical datastructures that can be used to efficiently encode all possible transformations, and then select the best transformation.</p>
|
||
<p>An example implementation is <a href="https://egraphs-good.github.io/">egg</a></p>
|
||
<p>Even though E-Graphs solve most problems, I still recommend using a pattern matching dialect, especially in multi-level compilers, to be more flexible, and have more future-proof pattern matching, or you decide that you want to match some complex patterns manually.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>More Advantages of Structured Pattern Matching</h2>
|
||
<h3>Smart Pattern Matchers</h3>
|
||
<p>Instead of brute-forcing all peephole optimizations (of which there can be a LOT in advanced compilers), the compiler can organize all the patterns to provide more efficient matching. I didn’t yet investigate how to do this. If you have any ideas regarding this, please <a href="https://alex.vxcc.dev">contact me.</a></p>
|
||
<p>There are other ways to speed up the pattern matching and rewrite process using this too.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Reversible Transformations</h3>
|
||
<p>I don’t think that there currently is any compiler that does this. If you do know one, again, please <a href="https://alex.vxcc.dev">contact me.</a></p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
"><br>Optimizing compilers typically deal with code (mostly written by people) that is on a lower level than the compiler theoretically supports. For example, humans tend to write code like this for extracting a bit: <code><code style="white-space: pre-wrap">x <span style="color: #d73a49">&amp;</span> (<span style="color: #b60157">1</span> <span style="color: #d73a49">&lt;&lt;</span> b)</code></code>, but compilers tend to have a high-level bit test operation (with exceptions). A reason for having higher-level primitives is that it allows the compiler to do more high-level optimizations, but also some target architectures have a bit test operation, that is more optimal.</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
"><br>This is not just the case for “low-level” things like bit tests, but also high level concepts, like a reduction over an array, or even the implementation of a whole algorithm. For example LLVM, since recently, can detect implementations of <a href="https://en.wikipedia.org/wiki/Cyclic_redundancy_check">CRC.</a></div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
"><br>LLVM actually doesn’t have many dedicated operations like a bit-test operation, and instead canonicalizes all bit-test patterns to <code><code style="white-space: pre-wrap">x <span style="color: #d73a49">&amp;</span> (<span style="color: #b60157">1</span> <span style="color: #d73a49">&lt;&lt;</span> b) <span style="color: #d73a49">!=</span> <span style="color: #b60157">0</span></code></code>, and matches for that in compiler passes that expect bit test operations.</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
"><br>Now let’s go back to the <code><code style="white-space: pre-wrap">x <span style="color: #d73a49">&amp;</span> (<span style="color: #b60157">1</span> <span style="color: #d73a49">&lt;&lt;</span> b)</code></code> (bit test) example. Optimizing compilers should be able to detect that, and other bit test patterns (like <code><code style="white-space: pre-wrap">x <span style="color: #d73a49">&amp;</span> (<span style="color: #b60157">1</span> <span style="color: #d73a49">&lt;&lt;</span> b) <span style="color: #d73a49">></span> <span style="color: #b60157">0</span></code></code>), and then replace those with a bit-test operation. But they also have to be able to convert bit-test operations back to their implementation for compilation targets that don’t have a bit-test instruction. Currently, compiler backends do this by having separate patterns for converting bit-test to it’s dedicated operation, and back.</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br>A better solution is to associate a set of implementations with the bit test operation, and make the compiler <strong>automatically reverse</strong> those to generate the best implementation (in the instruction selector for example).</p>
|
||
<p>Implementing pattern/transformation reversion can be challenging however, but it provides many benefits, and all “big” compilers should definitely do this, in my opinion.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Runtime Library</h3>
|
||
<p>Compilers typically come with a runtime library that implement more complex operations that aren’t supported by most processors or architectures.</p>
|
||
<p>The implementation of those functions should also use that pattern matching dialect. This allows your backend to detect code written by users with a similar implementation as in the runtime library, giving you some additional optimizations for free.</p>
|
||
<p>I don’t think any compiler currently does this either.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Problems with Pattern Matching</h2>
|
||
<p>The main problem is ordering the patterns.</p>
|
||
<p>As an example, consider these three patterns:</p>
|
||
<p><code><pre><code><span style="color: #8a8a8a">;;</span><span style="color: #8a8a8a"> A</span><br>(<span style="color: #4b69c6">add</span> x:Const y) => (<span style="color: #4b69c6">add</span> y x)<br><br><span style="color: #8a8a8a">;;</span><span style="color: #8a8a8a"> B</span><br>(<span style="color: #4b69c6">sub</span> (<span style="color: #4b69c6">add</span> x y:Const) z:Const) => (<span style="color: #4b69c6">lea</span> x y (<span style="color: #4b69c6">const_neg</span> z))<br><br><span style="color: #8a8a8a">;;</span><span style="color: #8a8a8a"> C</span><br>(<span style="color: #4b69c6">add</span> x <span style="color: #b60157">1</span>) => (<span style="color: #4b69c6">inc</span> x)</code></pre></code></p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br>Now what should the compiler do when it sees this:</p>
|
||
<p><code><pre><code>(<span style="color: #4b69c6">sub</span> (<span style="color: #4b69c6">add</span> <span style="color: #b60157">5</span> <span style="color: #b60157">1</span>) <span style="color: #b60157">2</span>)</code></pre></code></p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br>All three patterns would match:</p>
|
||
<p><code><pre><code><span style="color: #8a8a8a">;;</span><span style="color: #8a8a8a"> apply A</span><br>(<span style="color: #4b69c6">sub</span> (<span style="color: #4b69c6">add</span> <span style="color: #b60157">5</span> <span style="color: #b60157">1</span>) <span style="color: #b60157">2</span>) => (<span style="color: #4b69c6">sub</span> (<span style="color: #4b69c6">add</span> <span style="color: #b60157">1</span> <span style="color: #b60157">5</span>) <span style="color: #b60157">2</span>)<br><span style="color: #8a8a8a">;;</span><span style="color: #8a8a8a"> only B applies now</span><br>(<span style="color: #4b69c6">sub</span> (<span style="color: #4b69c6">add</span> <span style="color: #b60157">1</span> <span style="color: #b60157">5</span>) <span style="color: #b60157">2</span>) => (<span style="color: #4b69c6">lea</span> <span style="color: #b60157">1</span> <span style="color: #b60157">5</span> (<span style="color: #4b69c6">const_neg</span> <span style="color: #b60157">2</span>))<br><span style="color: #8a8a8a">;;</span><span style="color: #8a8a8a"> nothing applies anymore</span><br><br><span style="color: #8a8a8a">;;</span><span style="color: #8a8a8a"> alternatively apply B</span><br>(<span style="color: #4b69c6">sub</span> (<span style="color: #4b69c6">add</span> <span style="color: #b60157">5</span> <span style="color: #b60157">1</span>) <span style="color: #b60157">2</span>) => (<span style="color: #4b69c6">lea</span> <span style="color: #b60157">5</span> <span style="color: #b60157">1</span> (<span style="color: #4b69c6">const_neg</span> <span style="color: #b60157">2</span>))<br><span style="color: #8a8a8a">;;</span><span style="color: #8a8a8a"> nothing applies anymore</span><br><br><span style="color: #8a8a8a">;;</span><span style="color: #8a8a8a"> atlernatively apply C</span><br>(<span style="color: #4b69c6">sub</span> (<span style="color: #4b69c6">add</span> <span style="color: #b60157">5</span> <span style="color: #b60157">1</span>) <span style="color: #b60157">2</span>) => (<span style="color: #4b69c6">sub</span> (<span style="color: #4b69c6">inc</span> <span style="color: #b60157">5</span>) <span style="color: #b60157">2</span>)<br><span style="color: #8a8a8a">;;</span><span style="color: #8a8a8a"> nothing applies anymore</span></code></pre></code></p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br>Now which of those transformations should be performed?</p>
|
||
<p>This is not as easy to solve as it seems, especially in the context of instruction selection (specifically scheduling), where the performance on processors depends on a sequence of instructions, instead of just a single instruction.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Superscalar CPUs</h3>
|
||
<p>Modern processor architecture features like superscalar execution make this even more complicated.</p>
|
||
<p><br>As a simple, <strong>unrealistic</strong> example, let’s imagine a CPU (core) that has one bit operations execution unit, and two ALU execution units / ports.<br>This means that the CPU can execute two instructions in the ALU unit and one instruction in the bit ops unit at the same time.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br>One might think that always optimizing <code><code style="white-space: pre-wrap">a &amp; (1 &lt;&lt; b)</code></code> to a bit test operation is good for performance. But in this example, that is not the case.</p>
|
||
<p>If we have a function that does a lot of bitwise operations next to each other, and the compiler replaces all bit tests with bit test operations, suddenly all operations depend on the bit ops unit, which means that instead of executing 3 instructions at a time (ignoring pipelining), the CPU can only execute one instruction at a time.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br>This shows that we won’t know if an optimization is actually good, until we are at a late point in the compilation process where we can simulate the CPU’s instruction scheduling.</p>
|
||
<p>This does not only apply to instruction selection, but also to more higher-level optimizations, such as loop and control flow related optimizations.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Conclusion</h2>
|
||
<p>One can see how pattern matching dialects are the best option to approach pattern matching.</p>
|
||
<p><br>Someone wanted me to insert a takeaway here, but I won’t.</p>
|
||
<p><br>PS: I’ll hunt down everyone who still decides to do pattern matching in their compiler source after reading this article.</p>
|
||
</div>
|
||
</body>
|
||
</html>
|
||
</content><link href="compiler-pattern-matching.typ.desktop.html"/><summary>If you are working an more advanced compilers, you probably had to work with pattern matching already. In this article, we will explore different approaches.</summary></entry><entry><id>https://vxcc.dev/alex/article-favicon.typ.desktop.html</id><title>The making of the favicon</title><updated>2025-07-26T15:04:04+02:00</updated><author><name>Alexander Nutz</name><email>nutz.alexander@vxcc.dev</email><uri>https://alex.vxcc.dev</uri></author><content type="html"><!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<title>The making of the favicon</title>
|
||
<meta charset="utf-8">
|
||
</head>
|
||
<body>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h1>The making of the favicon</h1>
|
||
<p><span style="font-size: 9pt"><p>Last modified: 26. July 2025 15:04 (Git #<code><code style="white-space: pre-wrap">c80eb6ef</code></code>)</p><p>Written by <a href="https://alex.vxcc.dev">alex_s168</a></p></span></p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br>The favicon of my website currently is:</p>
|
||
<img src="res/favicon.png" alt="image" style="width:38%;">
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
"><br>This represents an <a href="https://www.sciencedirect.com/science/article/pii/S0890540197926432">interaction combinator</a> tree, that can be interpreted as a <a href="https://en.wikipedia.org/wiki/Lambda_calculus">lambda calculus</a> expression.</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Step 0: Designing the Circuit</h2>
|
||
<p>I ended up with this:</p>
|
||
<img src="res/article-favicon/step0.png" alt="image" style="width:32%;">
|
||
<p>(this is the second attempt at layouting the circuit)</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Step 1: Sketching</h2>
|
||
<p>While starting doing this, I realised that one wire always overlaps with one node triangle, unless I cheated. Here is a visual representation of this (inaccurate):</p>
|
||
<img src="res/article-favicon/step1_0.png" alt="image" style="width:18%;">
|
||
<p><br>This means that I have to modify the layouting from step 0 a bit, which is unfortunate, but in retrospect, I think that it makes the result look better:</p>
|
||
<img src="res/article-favicon/step1_1.png" alt="image" style="width:25%;">
|
||
<p><br>That however takes up too much space, so I did another variation:</p>
|
||
<img src="res/article-favicon/step1_2.png" alt="image" style="width:25%;">
|
||
<p><br>I also did another variation here, but decided to not use that.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Step 2: Preparation for coloring</h2>
|
||
<p>I colored the back side of the piece of paper which contains the sketeches with a pencil, put a white piece of paper behind it, and then re-traced the line, to get a lighter version of the sketch onto the white paper.</p>
|
||
<img src="res/article-favicon/step2.png" alt="image" style="width:25%;">
|
||
<p><br>Then I used modern technology (a copier) to copy that piece of paper multiple times, and also scale it up (to allow for more details).</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Step 3: Coloring</h2>
|
||
<p>It was a disaster…</p>
|
||
<img src="res/article-favicon/step3_0.png" alt="image" style="width:70%;">
|
||
<p><br></p>
|
||
<img src="res/article-favicon/step3_1.png" alt="image" style="width:70%;">
|
||
<p><br>Some variants actually look nice, but only parts of it.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Step 4: Outsourcing the coloring</h2>
|
||
<p>After some time, I just gave up, and decided to ask my sister for help…</p>
|
||
<img src="res/article-favicon/step4_0.png" alt="image" style="width:70%;">
|
||
<p><br>I only told her (translated):</p>
|
||
<p><code><pre><code>Can you please color this?<br>It's supposed to be a circuit, and it will be a small logo for a website.<br>The website is mainly black and white, but this (context: persian blue) blue would work too.</code></pre></code></p>
|
||
<p>And less than half a minute later, she came up with this:</p>
|
||
<img src="res/article-favicon/step4_1.png" alt="image" style="width:38%;">
|
||
<p><br>We considered that the logo will end up being quite small, so “we” wanted it to look good when zoomed out. This is a pretty nice idea, because the different colored wires end up blending together nicely.</p>
|
||
<p><br>I put that into the scanner, and meanwhile she experimented with different filling styles.</p>
|
||
<p><br>Then she came up with this (the final version):</p>
|
||
<img src="res/article-favicon/step4_2.png" alt="image" style="width:38%;">
|
||
<p>Filling the drawing only took her about 20 seconds!</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Step 5: Digital Modifications</h2>
|
||
<p>As last step, I removed some of the sketch lines and some minor imperfections digitally.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Conclusion</h2>
|
||
<p>I like the final result a lot (as small logo), but it’s a bit too detailed as favicon.</p>
|
||
<p>I will re-visit this topic in the future.</p>
|
||
</div>
|
||
</body>
|
||
</html>
|
||
</content><link href="article-favicon.typ.desktop.html"/><summary>It turns out that websites need a favicon, and making one is hard...</summary></entry><entry><id>https://vxcc.dev/alex/article-make-regex-engine-1.typ.desktop.html</id><title>Making a simple RegEx engine:
|
||
Part 1: Introduction to RegEx</title><updated>2025-07-26T14:20:22+02:00</updated><author><name>Alexander Nutz</name><email>nutz.alexander@vxcc.dev</email><uri>https://alex.vxcc.dev</uri></author><content type="html"><!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<title>Introduction to RegEx</title>
|
||
<meta charset="utf-8">
|
||
</head>
|
||
<body>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h1>Making a simple RegEx engine:
|
||
Part 1: Introduction to RegEx</h1>
|
||
<p><span style="font-size: 9pt"><p>Last modified: 26. July 2025 14:20 (Git #<code><code style="white-space: pre-wrap">fee2a364</code></code>)</p><p>Written by <a href="https://alex.vxcc.dev">alex_s168</a></p></span></p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Introduction</h2>
|
||
<p>If you are any kind of programmer, you’ve probably heard of <a href="https://en.wikipedia.org/wiki/Regular_expression">RegEx</a></p>
|
||
<p>RegEx (Regular expression) is kind of like a small programming language used to define string search and replace patterns.</p>
|
||
<p><br>RegEx might seem overwhelming at first, but you can learn the most important features of RegEx very quickly.</p>
|
||
<p><br>It is important to mention that there is not a single standard for RegEx syntax, but instead each “implementation” has it’s own quirks, and additional features. Most common features however behave identically on most RegEx “engines”/implementations.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Syntax</h2>
|
||
<p>The behavior of RegEx expressions / patterns depends on the match options passed to the RegEx engine.</p>
|
||
<p>Common match options<span id="match-options">:</span></p>
|
||
<ul>
|
||
<li>Anchored at start and end of line</li>
|
||
<li>Case insensitive</li>
|
||
<li>multi-line or instead whole string</li>
|
||
</ul>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>“Atoms”</h3>
|
||
<p>In this article, we will refer to single expression parts as “atoms”.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h4>Characters</h4>
|
||
<p>Just use the character that you want to match. For example <code><code style="white-space: pre-wrap">a</code></code> to match an <code><code style="white-space: pre-wrap">a</code></code>. This however does not work for all characters, because many are part of special RegEx syntax.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h4 id="escaped-chars">Escaped Characters</h4>
|
||
<p>Thee previously mentioned special characters like <code><code style="white-space: pre-wrap">[</code></code> can be matched by putting a backslash in front of them: <code><code style="white-space: pre-wrap"><span style="color: #1d6c76">\[</span></code></code></p>
|
||
<svg class="typst-frame" style="overflow: visible; width: 21.265625em; height: 5.279296875em;" viewBox="0 0 212.65625 52.79296875" width="212.65625pt" height="52.79296875pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:h5="http://www.w3.org/1999/xhtml"><g><g transform="translate(0 0)"><g class="typst-group"><g><g transform="translate(0 -0.5)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 53.79297 "/></g><g transform="translate(52.1435546875 -0.5)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 53.79297 "/></g><g transform="translate(212.65625 -0.5)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 53.79297 "/></g><g transform="translate(-0.5 0)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 213.65625 0 "/></g><g transform="translate(-0.5 17.59765625)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 213.65625 0 "/></g><g transform="translate(-0.5 35.1953125)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 213.65625 0 "/></g><g transform="translate(-0.5 52.79296875)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 213.65625 0 "/></g><g transform="translate(5 12.59765625)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#gA9630BC7DC7C1A3B2772AC4EAF5E6A4E" x="0" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="6.0205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="12.041015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="18.0615234375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="24.08203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="30.1025390625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="36.123046875" y="0" fill="#000000" fill-rule="nonzero"/></g></g><g transform="translate(57.1435546875 12.59765625)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#gF2D21C82F46AFB157CA5E1AB14665E2F" x="0" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="6.0205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g23E41626515445E1BB7071D28C59ADA4" x="12.041015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="18.0615234375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="24.08203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="30.1025390625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gC5CB98F12AF1494D83D230F6647F5A66" x="36.123046875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="42.1435546875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="48.1640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDAC4E5B9EA78940BD8041CFC64F1642E" x="54.1845703125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="60.205078125" y="0" fill="#000000" fill-rule="nonzero"/></g></g><g transform="translate(0 17.59765625)"><g class="typst-group"><g><g transform="translate(5 11.078125)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#gD3E02A90146443F5D1C908F343BC0F25" x="0" y="0" fill="#1d6c76" fill-rule="nonzero"/><use xlink:href="#gD3E02A90146443F5D1C908F343BC0F25" x="4.81640625" y="0" fill="#1d6c76" fill-rule="nonzero"/></g></g><g transform="translate(57.1435546875 12.59765625)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#gB83FD8DF61FB2E4EAD552878F3E8DD3F" x="0" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="6.0205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="12.041015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="18.0615234375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g54B52F8AE89AD429D6D3AD95B2D89739" x="24.08203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="36.123046875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g961CAE06C7AAE8EB428417D81D5AEE72" x="48.1640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="54.1845703125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="60.205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="66.2255859375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="72.24609375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="78.2666015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g961CAE06C7AAE8EB428417D81D5AEE72" x="84.287109375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g77AA3201A93C8F4113E19CCDA185B6F5" x="96.328125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="102.3486328125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="108.369140625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g958F64BF87063D7EAFEDE953DDA2BF9F" x="114.3896484375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g23E41626515445E1BB7071D28C59ADA4" x="120.41015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g961CAE06C7AAE8EB428417D81D5AEE72" x="126.4306640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="132.451171875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g23E41626515445E1BB7071D28C59ADA4" x="138.4716796875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g54B52F8AE89AD429D6D3AD95B2D89739" x="144.4921875" y="0" fill="#000000" fill-rule="nonzero"/></g></g></g></g></g><g transform="translate(0 35.1953125)"><g class="typst-group"><g><g transform="translate(5 11.078125)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#gD3E02A90146443F5D1C908F343BC0F25" x="0" y="0" fill="#1d6c76" fill-rule="nonzero"/><use xlink:href="#g1E73FB87418835A88E58B2B7006EB72B" x="4.81640625" y="0" fill="#1d6c76" fill-rule="nonzero"/></g></g><g transform="translate(57.1435546875 12.59765625)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#gB83FD8DF61FB2E4EAD552878F3E8DD3F" x="0" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="6.0205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="12.041015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="18.0615234375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g54B52F8AE89AD429D6D3AD95B2D89739" x="24.08203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="36.123046875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="48.1640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="54.1845703125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g3D5EE249F6894FA38DD21E85E2FD5F05" x="60.205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gD77243764E4306BD6D683907293F12D5" x="66.2255859375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g961CAE06C7AAE8EB428417D81D5AEE72" x="72.24609375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="78.2666015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="84.287109375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="90.3076171875" y="0" fill="#000000" fill-rule="nonzero"/></g></g></g></g></g></g></g></g></g><defs id="glyph"><symbol id="gA9630BC7DC7C1A3B2772AC4EAF5E6A4E" overflow="visible"><path d="M 1.9482422 6.479492 L 1.9482422 3.7402344 L 3.0908203 3.7402344 Q 3.774414 3.7402344 4.157715 4.1015625 Q 4.5410156 4.4628906 4.5410156 5.1123047 Q 4.5410156 5.7617188 4.1601563 6.1206055 Q 3.7792969 6.479492 3.0908203 6.479492 L 1.9482422 6.479492 Z M 0.96191406 7.290039 L 3.0908203 7.290039 Q 4.3115234 7.290039 4.9414063 6.73584 Q 5.571289 6.1816406 5.571289 5.1123047 Q 5.571289 4.033203 4.9438477 3.4814453 Q 4.3164063 2.9296875 3.0908203 2.9296875 L 1.9482422 2.9296875 L 1.9482422 0 L 0.96191406 0 L 0.96191406 7.290039 Z "/></symbol><symbol id="g37BF1C0F714F2658F35D194C9E053C6F" overflow="visible"><path d="M 3.4277344 2.7490234 L 3.1298828 2.7490234 Q 2.34375 2.7490234 1.9458008 2.4731445 Q 1.5478516 2.1972656 1.5478516 1.6503906 Q 1.5478516 1.1572266 1.8457031 0.88378906 Q 2.1435547 0.61035156 2.6708984 0.61035156 Q 3.413086 0.61035156 3.8378906 1.1254883 Q 4.2626953 1.640625 4.267578 2.5488281 L 4.267578 2.7490234 L 3.4277344 2.7490234 Z M 5.1708984 3.1201172 L 5.1708984 0 L 4.267578 0 L 4.267578 0.8105469 Q 3.9794922 0.32226563 3.5424805 0.09033203 Q 3.1054688 -0.14160156 2.4804688 -0.14160156 Q 1.6455078 -0.14160156 1.1474609 0.32958984 Q 0.64941406 0.80078125 0.64941406 1.5917969 Q 0.64941406 2.5048828 1.262207 2.9785156 Q 1.875 3.4521484 3.0615234 3.4521484 L 4.267578 3.4521484 L 4.267578 3.59375 Q 4.2626953 4.248047 3.9355469 4.543457 Q 3.6083984 4.838867 2.890625 4.838867 Q 2.4316406 4.838867 1.9628906 4.7070313 Q 1.4941406 4.5751953 1.0498047 4.321289 L 1.0498047 5.2197266 Q 1.5478516 5.4101563 2.0043945 5.505371 Q 2.4609375 5.600586 2.890625 5.600586 Q 3.569336 5.600586 4.050293 5.4003906 Q 4.53125 5.2001953 4.8291016 4.7998047 Q 5.0146484 4.555664 5.0927734 4.1967773 Q 5.1708984 3.8378906 5.1708984 3.1201172 Z "/></symbol><symbol id="g8EFE1C4A2E0CD0A03B7633D0C324134A" overflow="visible"><path d="M 2.9980469 7.0214844 L 2.9980469 5.46875 L 5.0390625 5.46875 L 5.0390625 4.770508 L 2.9980469 4.770508 L 2.9980469 1.8017578 Q 2.9980469 1.1962891 3.227539 0.95703125 Q 3.4570313 0.71777344 4.0283203 0.71777344 L 5.0390625 0.71777344 L 5.0390625 0 L 3.9404297 0 Q 2.9296875 0 2.5146484 0.40527344 Q 2.0996094 0.8105469 2.0996094 1.8017578 L 2.0996094 4.770508 L 0.63964844 4.770508 L 0.63964844 5.46875 L 2.0996094 5.46875 L 2.0996094 7.0214844 L 2.9980469 7.0214844 Z "/></symbol><symbol id="g9CEA08D585A10BDF30AE748A6F2738E3" overflow="visible"><path d="M 5.4296875 2.9589844 L 5.4296875 2.5195313 L 1.5380859 2.5195313 L 1.5380859 2.4902344 Q 1.5380859 1.5966797 2.0043945 1.1083984 Q 2.4707031 0.6201172 3.3203125 0.6201172 Q 3.75 0.6201172 4.21875 0.75683594 Q 4.6875 0.8935547 5.2197266 1.171875 L 5.2197266 0.2783203 Q 4.7070313 0.068359375 4.230957 -0.036621094 Q 3.7548828 -0.14160156 3.3105469 -0.14160156 Q 2.0361328 -0.14160156 1.3183594 0.6225586 Q 0.60058594 1.3867188 0.60058594 2.7294922 Q 0.60058594 4.038086 1.3037109 4.819336 Q 2.006836 5.600586 3.178711 5.600586 Q 4.223633 5.600586 4.82666 4.892578 Q 5.4296875 4.1845703 5.4296875 2.9589844 Z M 4.53125 3.2226563 Q 4.5117188 4.013672 4.157715 4.4262695 Q 3.803711 4.838867 3.1396484 4.838867 Q 2.4902344 4.838867 2.0703125 4.4091797 Q 1.6503906 3.9794922 1.5722656 3.2177734 L 4.53125 3.2226563 Z "/></symbol><symbol id="g8B1CFD5A71F51FD444694A31ACE7ED10" overflow="visible"><path d="M 5.6396484 4.3408203 Q 5.3515625 4.5654297 5.053711 4.6679688 Q 4.7558594 4.770508 4.399414 4.770508 Q 3.5595703 4.770508 3.1152344 4.243164 Q 2.6708984 3.7158203 2.6708984 2.7197266 L 2.6708984 0 L 1.7675781 0 L 1.7675781 5.46875 L 2.6708984 5.46875 L 2.6708984 4.399414 Q 2.8955078 4.9804688 3.3618164 5.2905273 Q 3.828125 5.600586 4.4677734 5.600586 Q 4.7998047 5.600586 5.0878906 5.517578 Q 5.3759766 5.4345703 5.6396484 5.258789 L 5.6396484 4.3408203 Z "/></symbol><symbol id="gDDF33CCACF8520FD5879FCDAE37BD86" overflow="visible"><path d="M 5.131836 3.3886719 L 5.131836 0 L 4.2285156 0 L 4.2285156 3.3886719 Q 4.2285156 4.1259766 3.9697266 4.4726563 Q 3.7109375 4.819336 3.1591797 4.819336 Q 2.5292969 4.819336 2.1899414 4.3725586 Q 1.8505859 3.9257813 1.8505859 3.0908203 L 1.8505859 0 L 0.95214844 0 L 0.95214844 5.46875 L 1.8505859 5.46875 L 1.8505859 4.6484375 Q 2.0898438 5.1171875 2.5 5.3588867 Q 2.9101563 5.600586 3.4716797 5.600586 Q 4.3066406 5.600586 4.7192383 5.0512695 Q 5.131836 4.501953 5.131836 3.3886719 Z "/></symbol><symbol id="gF2D21C82F46AFB157CA5E1AB14665E2F" overflow="visible"><path d="M 2.1289063 0.8105469 Q 3.3740234 0.8105469 3.8671875 1.4233398 Q 4.3603516 2.0361328 4.3603516 3.6376953 Q 4.3603516 5.2539063 3.869629 5.866699 Q 3.3789063 6.479492 2.1289063 6.479492 L 1.6601563 6.479492 L 1.6601563 0.8105469 L 2.1289063 0.8105469 Z M 2.1484375 7.290039 Q 3.8183594 7.290039 4.609375 6.401367 Q 5.4003906 5.5126953 5.4003906 3.6376953 Q 5.4003906 1.7724609 4.609375 0.88623047 Q 3.8183594 0 2.1484375 0 L 0.6689453 0 L 0.6689453 7.290039 L 2.1484375 7.290039 Z "/></symbol><symbol id="g23E41626515445E1BB7071D28C59ADA4" overflow="visible"><path d="M 4.7509766 5.2783203 L 4.7509766 4.399414 Q 4.3652344 4.6240234 3.9746094 4.736328 Q 3.5839844 4.848633 3.178711 4.848633 Q 2.5683594 4.848633 2.2680664 4.650879 Q 1.9677734 4.453125 1.9677734 4.0478516 Q 1.9677734 3.6816406 2.1923828 3.5009766 Q 2.4169922 3.3203125 3.3105469 3.149414 L 3.671875 3.0810547 Q 4.3408203 2.9541016 4.6850586 2.5732422 Q 5.029297 2.1923828 5.029297 1.5820313 Q 5.029297 0.7714844 4.453125 0.3149414 Q 3.8769531 -0.14160156 2.8515625 -0.14160156 Q 2.446289 -0.14160156 2.0019531 -0.056152344 Q 1.5576172 0.029296875 1.0400391 0.20019531 L 1.0400391 1.1279297 Q 1.5429688 0.8691406 2.0019531 0.7397461 Q 2.4609375 0.61035156 2.8710938 0.61035156 Q 3.4667969 0.61035156 3.7939453 0.8520508 Q 4.1210938 1.09375 4.1210938 1.5283203 Q 4.1210938 2.1533203 2.9248047 2.3925781 L 2.8857422 2.4023438 L 2.5488281 2.4707031 Q 1.7724609 2.6220703 1.4160156 2.980957 Q 1.0595703 3.3398438 1.0595703 3.959961 Q 1.0595703 4.7460938 1.5917969 5.17334 Q 2.1240234 5.600586 3.1103516 5.600586 Q 3.5498047 5.600586 3.9550781 5.5200195 Q 4.3603516 5.439453 4.7509766 5.2783203 Z "/></symbol><symbol id="gAB79A30431405AF14CCB1B23143BD7F1" overflow="visible"><path d="M 5.180664 0.2783203 Q 4.819336 0.068359375 4.436035 -0.036621094 Q 4.0527344 -0.14160156 3.6523438 -0.14160156 Q 2.3828125 -0.14160156 1.6674805 0.6201172 Q 0.95214844 1.3818359 0.95214844 2.7294922 Q 0.95214844 4.0771484 1.6674805 4.838867 Q 2.3828125 5.600586 3.6523438 5.600586 Q 4.0478516 5.600586 4.423828 5.498047 Q 4.7998047 5.395508 5.180664 5.180664 L 5.180664 4.2382813 Q 4.8242188 4.555664 4.465332 4.6972656 Q 4.1064453 4.838867 3.6523438 4.838867 Q 2.8076172 4.838867 2.3535156 4.291992 Q 1.8994141 3.7451172 1.8994141 2.7294922 Q 1.8994141 1.71875 2.355957 1.1694336 Q 2.8125 0.6201172 3.6523438 0.6201172 Q 4.1210938 0.6201172 4.4921875 0.76416016 Q 4.8632813 0.9082031 5.180664 1.2109375 L 5.180664 0.2783203 Z "/></symbol><symbol id="gF1D16D3439F586916205801D07D97589" overflow="visible"><path d="M 1.25 5.46875 L 3.5498047 5.46875 L 3.5498047 0.6982422 L 5.3320313 0.6982422 L 5.3320313 0 L 0.8691406 0 L 0.8691406 0.6982422 L 2.6513672 0.6982422 L 2.6513672 4.770508 L 1.25 4.770508 L 1.25 5.46875 Z M 2.6513672 7.5976563 L 3.5498047 7.5976563 L 3.5498047 6.459961 L 2.6513672 6.459961 L 2.6513672 7.5976563 Z "/></symbol><symbol id="gC5CB98F12AF1494D83D230F6647F5A66" overflow="visible"><path d="M 1.8310547 0.68847656 L 1.8310547 -2.0800781 L 0.9277344 -2.0800781 L 0.9277344 5.46875 L 1.8310547 5.46875 L 1.8310547 4.770508 Q 2.055664 5.1757813 2.4291992 5.3881836 Q 2.8027344 5.600586 3.2910156 5.600586 Q 4.2822266 5.600586 4.8461914 4.8339844 Q 5.4101563 4.067383 5.4101563 2.709961 Q 5.4101563 1.3769531 4.84375 0.6176758 Q 4.2773438 -0.14160156 3.2910156 -0.14160156 Q 2.7929688 -0.14160156 2.4194336 0.07080078 Q 2.0458984 0.28320313 1.8310547 0.68847656 Z M 4.4677734 2.7294922 Q 4.4677734 3.774414 4.1381836 4.3066406 Q 3.8085938 4.838867 3.1591797 4.838867 Q 2.5048828 4.838867 2.1679688 4.304199 Q 1.8310547 3.7695313 1.8310547 2.7294922 Q 1.8310547 1.6943359 2.1679688 1.1572266 Q 2.5048828 0.6201172 3.1591797 0.6201172 Q 3.8085938 0.6201172 4.1381836 1.1523438 Q 4.4677734 1.6845703 4.4677734 2.7294922 Z "/></symbol><symbol id="gDAC4E5B9EA78940BD8041CFC64F1642E" overflow="visible"><path d="M 3.0078125 4.838867 Q 2.3242188 4.838867 1.9726563 4.3066406 Q 1.6210938 3.774414 1.6210938 2.7294922 Q 1.6210938 1.6894531 1.9726563 1.1547852 Q 2.3242188 0.6201172 3.0078125 0.6201172 Q 3.696289 0.6201172 4.0478516 1.1547852 Q 4.399414 1.6894531 4.399414 2.7294922 Q 4.399414 3.774414 4.0478516 4.3066406 Q 3.696289 4.838867 3.0078125 4.838867 Z M 3.0078125 5.600586 Q 4.145508 5.600586 4.748535 4.8632813 Q 5.3515625 4.1259766 5.3515625 2.7294922 Q 5.3515625 1.328125 4.7509766 0.5932617 Q 4.1503906 -0.14160156 3.0078125 -0.14160156 Q 1.8701172 -0.14160156 1.2695313 0.5932617 Q 0.6689453 1.328125 0.6689453 2.7294922 Q 0.6689453 4.1259766 1.2695313 4.8632813 Q 1.8701172 5.600586 3.0078125 5.600586 Z "/></symbol><symbol id="gD3E02A90146443F5D1C908F343BC0F25" overflow="visible"><path d="M 1.1445313 5.8320313 L 4.2148438 -0.7421875 L 3.4726563 -0.7421875 L 0.3984375 5.8320313 L 1.1445313 5.8320313 Z "/></symbol><symbol id="gB83FD8DF61FB2E4EAD552878F3E8DD3F" overflow="visible"><path d="M 3.3007813 4.9121094 Q 3.4667969 5.263672 3.7231445 5.432129 Q 3.9794922 5.600586 4.3408203 5.600586 Q 5 5.600586 5.270996 5.090332 Q 5.541992 4.580078 5.541992 3.1689453 L 5.541992 0 L 4.7216797 0 L 4.7216797 3.1298828 Q 4.7216797 4.2871094 4.592285 4.567871 Q 4.4628906 4.848633 4.1210938 4.848633 Q 3.7304688 4.848633 3.5864258 4.54834 Q 3.4423828 4.248047 3.4423828 3.1298828 L 3.4423828 0 L 2.6220703 0 L 2.6220703 3.1298828 Q 2.6220703 4.301758 2.4829102 4.5751953 Q 2.34375 4.848633 1.9824219 4.848633 Q 1.6259766 4.848633 1.4868164 4.54834 Q 1.3476563 4.248047 1.3476563 3.1298828 L 1.3476563 0 L 0.53222656 0 L 0.53222656 5.46875 L 1.3476563 5.46875 L 1.3476563 5 Q 1.5087891 5.2929688 1.7504883 5.4467773 Q 1.9921875 5.600586 2.2998047 5.600586 Q 2.6708984 5.600586 2.9174805 5.4296875 Q 3.1640625 5.258789 3.3007813 4.9121094 Z "/></symbol><symbol id="g54B52F8AE89AD429D6D3AD95B2D89739" overflow="visible"><path d="M 5.131836 3.3886719 L 5.131836 0 L 4.2285156 0 L 4.2285156 3.3886719 Q 4.2285156 4.1259766 3.9697266 4.4726563 Q 3.7109375 4.819336 3.1591797 4.819336 Q 2.5292969 4.819336 2.1899414 4.3725586 Q 1.8505859 3.9257813 1.8505859 3.0908203 L 1.8505859 0 L 0.95214844 0 L 0.95214844 7.5976563 L 1.8505859 7.5976563 L 1.8505859 4.6484375 Q 2.0898438 5.1171875 2.5 5.3588867 Q 2.9101563 5.600586 3.4716797 5.600586 Q 4.3066406 5.600586 4.7192383 5.0512695 Q 5.131836 4.501953 5.131836 3.3886719 Z "/></symbol><symbol id="g961CAE06C7AAE8EB428417D81D5AEE72" overflow="visible"><path d="M 3.1201172 1.9824219 Q 3.1201172 1.3769531 3.3422852 1.0693359 Q 3.5644531 0.76171875 3.9990234 0.76171875 L 5.048828 0.76171875 L 5.048828 0 L 3.9111328 0 Q 3.1054688 0 2.6635742 0.5175781 Q 2.2216797 1.0351563 2.2216797 1.9824219 L 2.2216797 6.948242 L 0.78125 6.948242 L 0.78125 7.651367 L 3.1201172 7.651367 L 3.1201172 1.9824219 Z "/></symbol><symbol id="g77AA3201A93C8F4113E19CCDA185B6F5" overflow="visible"><path d="M 4.482422 2.7294922 Q 4.482422 3.774414 4.1503906 4.3066406 Q 3.8183594 4.838867 3.1689453 4.838867 Q 2.5146484 4.838867 2.1777344 4.304199 Q 1.8408203 3.7695313 1.8408203 2.7294922 Q 1.8408203 1.6943359 2.1777344 1.1572266 Q 2.5146484 0.6201172 3.1689453 0.6201172 Q 3.8183594 0.6201172 4.1503906 1.1523438 Q 4.482422 1.6845703 4.482422 2.7294922 Z M 1.8408203 4.770508 Q 2.055664 5.1708984 2.434082 5.385742 Q 2.8125 5.600586 3.3105469 5.600586 Q 4.296875 5.600586 4.8632813 4.8413086 Q 5.4296875 4.0820313 5.4296875 2.7490234 Q 5.4296875 1.3964844 4.86084 0.6274414 Q 4.291992 -0.14160156 3.3007813 -0.14160156 Q 2.8125 -0.14160156 2.4389648 0.07080078 Q 2.0654297 0.28320313 1.8408203 0.68847656 L 1.8408203 0 L 0.9423828 0 L 0.9423828 7.5976563 L 1.8408203 7.5976563 L 1.8408203 4.770508 Z "/></symbol><symbol id="g958F64BF87063D7EAFEDE953DDA2BF9F" overflow="visible"><path d="M 1.1523438 7.5976563 L 2.0800781 7.5976563 L 2.0800781 3.1982422 L 4.4384766 5.46875 L 5.5322266 5.46875 L 3.3789063 3.4082031 L 5.8691406 0 L 4.770508 0 L 2.7490234 2.8222656 L 2.0800781 2.1923828 L 2.0800781 0 L 1.1523438 0 L 1.1523438 7.5976563 Z "/></symbol><symbol id="g1E73FB87418835A88E58B2B7006EB72B" overflow="visible"><path d="M 4.1054688 2.7109375 L 4.1054688 0 L 3.3828125 0 L 3.3828125 2.7109375 Q 3.3828125 3.3007813 3.1757813 3.578125 Q 2.96875 3.8554688 2.5273438 3.8554688 Q 2.0234375 3.8554688 1.7519531 3.4980469 Q 1.4804688 3.140625 1.4804688 2.4726563 L 1.4804688 0 L 0.76171875 0 L 0.76171875 4.375 L 1.4804688 4.375 L 1.4804688 3.71875 Q 1.671875 4.09375 2 4.2871094 Q 2.328125 4.4804688 2.7773438 4.4804688 Q 3.4453125 4.4804688 3.7753906 4.0410156 Q 4.1054688 3.6015625 4.1054688 2.7109375 Z "/></symbol><symbol id="g3D5EE249F6894FA38DD21E85E2FD5F05" overflow="visible"><path d="M 0 5.46875 L 0.8886719 5.46875 L 1.8408203 1.0498047 L 2.6220703 3.8720703 L 3.3886719 3.8720703 L 4.1796875 1.0498047 L 5.131836 5.46875 L 6.020508 5.46875 L 4.741211 0 L 3.881836 0 L 3.0078125 2.9980469 L 2.1386719 0 L 1.2792969 0 L 0 5.46875 Z "/></symbol><symbol id="gD77243764E4306BD6D683907293F12D5" overflow="visible"><path d="M 1.7382813 3.1396484 L 4.2822266 3.1396484 L 4.2822266 2.3388672 L 1.7382813 2.3388672 L 1.7382813 3.1396484 Z "/></symbol></defs></svg>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h4 id="char-groups">Character Groups</h4>
|
||
<p>RegEx engines already define some groups of characters that can make writing RegEx expressions quicker.</p>
|
||
<svg class="typst-frame" style="overflow: visible; width: 40.53125em; height: 14.078125em;" viewBox="0 0 405.3125 140.78125" width="405.3125pt" height="140.78125pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:h5="http://www.w3.org/1999/xhtml"><g><g transform="translate(0 0)"><g class="typst-group"><g><g transform="translate(0 -0.5)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 141.78125 "/></g><g transform="translate(52.1435546875 -0.5)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 141.78125 "/></g><g transform="translate(405.3125 -0.5)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 141.78125 "/></g><g transform="translate(-0.5 0)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 406.3125 0 "/></g><g transform="translate(-0.5 17.59765625)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 406.3125 0 "/></g><g transform="translate(-0.5 35.1953125)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 406.3125 0 "/></g><g transform="translate(-0.5 52.79296875)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 406.3125 0 "/></g><g transform="translate(-0.5 70.390625)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 406.3125 0 "/></g><g transform="translate(-0.5 87.98828125)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 406.3125 0 "/></g><g transform="translate(-0.5 105.5859375)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 406.3125 0 "/></g><g transform="translate(-0.5 123.18359375)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 406.3125 0 "/></g><g transform="translate(-0.5 140.78125)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 406.3125 0 "/></g><g transform="translate(5 12.59765625)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#gA9630BC7DC7C1A3B2772AC4EAF5E6A4E" x="0" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="6.0205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="12.041015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="18.0615234375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="24.08203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="30.1025390625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="36.123046875" y="0" fill="#000000" fill-rule="nonzero"/></g></g><g transform="translate(57.1435546875 12.59765625)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#gF2D21C82F46AFB157CA5E1AB14665E2F" x="0" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="6.0205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g23E41626515445E1BB7071D28C59ADA4" x="12.041015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="18.0615234375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="24.08203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="30.1025390625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gC5CB98F12AF1494D83D230F6647F5A66" x="36.123046875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="42.1435546875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="48.1640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDAC4E5B9EA78940BD8041CFC64F1642E" x="54.1845703125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="60.205078125" y="0" fill="#000000" fill-rule="nonzero"/></g></g><g transform="translate(0 17.59765625)"><g class="typst-group"><g><g transform="translate(5 11.078125)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#gE671651E4E76A7E6A66592123F7CB0EF" x="0" y="0" fill="#d73a49" fill-rule="nonzero"/></g></g><g transform="translate(57.1435546875 12.59765625)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="0" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="6.0205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g1FA38BF5C517F615C367E61F0044A197" x="12.041015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="24.08203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g54B52F8AE89AD429D6D3AD95B2D89739" x="30.1025390625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="36.123046875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="42.1435546875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="48.1640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="54.1845703125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="60.205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="66.2255859375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="72.24609375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="84.287109375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gBB49C9F26722473D147EE93A203A972A" x="90.3076171875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="96.328125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="102.3486328125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gC5CB98F12AF1494D83D230F6647F5A66" x="108.369140625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="114.3896484375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g1D505C2B8EC47EA4C26743DADEC508A3" x="126.4306640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDAC4E5B9EA78940BD8041CFC64F1642E" x="132.451171875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="138.4716796875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g961CAE06C7AAE8EB428417D81D5AEE72" x="150.5126953125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="156.533203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="162.5537109375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="168.57421875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g77AA3201A93C8F4113E19CCDA185B6F5" x="180.615234375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="186.6357421875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="192.65625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="198.6767578125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g958F64BF87063D7EAFEDE953DDA2BF9F" x="204.697265625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g23E41626515445E1BB7071D28C59ADA4" x="210.7177734375" y="0" fill="#000000" fill-rule="nonzero"/></g></g></g></g></g><g transform="translate(0 35.1953125)"><g class="typst-group"><g><g transform="translate(5 11.078125)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#gD3E02A90146443F5D1C908F343BC0F25" x="0" y="0" fill="#d73a49" fill-rule="nonzero"/><use xlink:href="#gC58E40CCEEAAE4A011790927FE560B0C" x="4.81640625" y="0" fill="#d73a49" fill-rule="nonzero"/></g></g><g transform="translate(57.1435546875 12.59765625)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="0" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="6.0205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g1FA38BF5C517F615C367E61F0044A197" x="12.041015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g3D5EE249F6894FA38DD21E85E2FD5F05" x="24.08203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g54B52F8AE89AD429D6D3AD95B2D89739" x="30.1025390625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="36.123046875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="42.1435546875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="48.1640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g23E41626515445E1BB7071D28C59ADA4" x="54.1845703125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gC5CB98F12AF1494D83D230F6647F5A66" x="60.205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="66.2255859375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="72.24609375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="78.2666015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDAC4E5B9EA78940BD8041CFC64F1642E" x="90.3076171875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="96.328125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g961CAE06C7AAE8EB428417D81D5AEE72" x="108.369140625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="114.3896484375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="120.41015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="126.4306640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g77AA3201A93C8F4113E19CCDA185B6F5" x="138.4716796875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="144.4921875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="150.5126953125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="156.533203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g958F64BF87063D7EAFEDE953DDA2BF9F" x="162.5537109375" y="0" fill="#000000" fill-rule="nonzero"/></g></g></g></g></g><g transform="translate(0 52.79296875)"><g class="typst-group"><g><g transform="translate(5 11.078125)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#gD3E02A90146443F5D1C908F343BC0F25" x="0" y="0" fill="#d73a49" fill-rule="nonzero"/><use xlink:href="#gF953090ED8E474A6BDB5C112B8614419" x="4.81640625" y="0" fill="#d73a49" fill-rule="nonzero"/></g></g><g transform="translate(57.1435546875 12.59765625)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="0" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="6.0205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g1FA38BF5C517F615C367E61F0044A197" x="12.041015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="24.08203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g54B52F8AE89AD429D6D3AD95B2D89739" x="30.1025390625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="36.123046875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="42.1435546875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="48.1640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="54.1845703125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="60.205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="66.2255859375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="72.24609375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="84.287109375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gBB49C9F26722473D147EE93A203A972A" x="90.3076171875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="96.328125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="102.3486328125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gC5CB98F12AF1494D83D230F6647F5A66" x="108.369140625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="114.3896484375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g3D5EE249F6894FA38DD21E85E2FD5F05" x="126.4306640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g54B52F8AE89AD429D6D3AD95B2D89739" x="132.451171875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="138.4716796875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="144.4921875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="150.5126953125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g23E41626515445E1BB7071D28C59ADA4" x="156.533203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gC5CB98F12AF1494D83D230F6647F5A66" x="162.5537109375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="168.57421875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="174.5947265625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="180.615234375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g23E41626515445E1BB7071D28C59ADA4" x="186.6357421875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDAC4E5B9EA78940BD8041CFC64F1642E" x="198.6767578125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="204.697265625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g961CAE06C7AAE8EB428417D81D5AEE72" x="216.73828125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="222.7587890625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="228.779296875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="234.7998046875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g77AA3201A93C8F4113E19CCDA185B6F5" x="246.8408203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="252.861328125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="258.8818359375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="264.90234375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g958F64BF87063D7EAFEDE953DDA2BF9F" x="270.9228515625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g23E41626515445E1BB7071D28C59ADA4" x="276.943359375" y="0" fill="#000000" fill-rule="nonzero"/></g></g></g></g></g><g transform="translate(0 70.390625)"><g class="typst-group"><g><g transform="translate(5 11.078125)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#gD3E02A90146443F5D1C908F343BC0F25" x="0" y="0" fill="#d73a49" fill-rule="nonzero"/><use xlink:href="#gF5F7ADACD3C8648021D0891B6403D353" x="4.81640625" y="0" fill="#d73a49" fill-rule="nonzero"/></g></g><g transform="translate(57.1435546875 12.59765625)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="0" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="6.0205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g1FA38BF5C517F615C367E61F0044A197" x="12.041015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g3402EB21D38B9A8AFC4DFC6262792511" x="24.08203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="30.1025390625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9E9C649267338B7BCF3BB51B9816396A" x="36.123046875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="42.1435546875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="48.1640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g1D505C2B8EC47EA4C26743DADEC508A3" x="60.205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="66.2255859375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDAC4E5B9EA78940BD8041CFC64F1642E" x="72.24609375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gB83FD8DF61FB2E4EAD552878F3E8DD3F" x="78.2666015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g807B89443FA0EF4D7A7A613982FE96F6" x="90.3076171875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="102.3486328125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDAC4E5B9EA78940BD8041CFC64F1642E" x="108.369140625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gA06F636B71996BA7070F256843DCE7EE" x="120.41015625" y="0" fill="#000000" fill-rule="nonzero"/></g></g></g></g></g><g transform="translate(0 87.98828125)"><g class="typst-group"><g><g transform="translate(5 11.078125)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#gD3E02A90146443F5D1C908F343BC0F25" x="0" y="0" fill="#d73a49" fill-rule="nonzero"/><use xlink:href="#g27C321132E0A6A9E6B99ED77584BAD53" x="4.81640625" y="0" fill="#d73a49" fill-rule="nonzero"/></g></g><g transform="translate(57.1435546875 12.59765625)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="0" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="6.0205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g1FA38BF5C517F615C367E61F0044A197" x="12.041015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="24.08203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g54B52F8AE89AD429D6D3AD95B2D89739" x="30.1025390625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="36.123046875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="42.1435546875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="48.1640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="54.1845703125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="60.205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="66.2255859375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="72.24609375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="84.287109375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gBB49C9F26722473D147EE93A203A972A" x="90.3076171875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="96.328125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="102.3486328125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gC5CB98F12AF1494D83D230F6647F5A66" x="108.369140625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="114.3896484375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g3402EB21D38B9A8AFC4DFC6262792511" x="126.4306640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="132.451171875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9E9C649267338B7BCF3BB51B9816396A" x="138.4716796875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="144.4921875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="150.5126953125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g23E41626515445E1BB7071D28C59ADA4" x="156.533203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g1D505C2B8EC47EA4C26743DADEC508A3" x="168.57421875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="174.5947265625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDAC4E5B9EA78940BD8041CFC64F1642E" x="180.615234375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gB83FD8DF61FB2E4EAD552878F3E8DD3F" x="186.6357421875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g807B89443FA0EF4D7A7A613982FE96F6" x="198.6767578125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="210.7177734375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDAC4E5B9EA78940BD8041CFC64F1642E" x="216.73828125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gA06F636B71996BA7070F256843DCE7EE" x="228.779296875" y="0" fill="#000000" fill-rule="nonzero"/></g></g></g></g></g><g transform="translate(0 105.5859375)"><g class="typst-group"><g><g transform="translate(5 11.078125)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#gD3E02A90146443F5D1C908F343BC0F25" x="0" y="0" fill="#d73a49" fill-rule="nonzero"/><use xlink:href="#g7342E383B6C704BD4B47D4672216B35D" x="4.81640625" y="0" fill="#d73a49" fill-rule="nonzero"/></g></g><g transform="translate(57.1435546875 12.59765625)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="0" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g961CAE06C7AAE8EB428417D81D5AEE72" x="12.041015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="18.0615234375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="24.08203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="30.1025390625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="36.123046875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="42.1435546875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gC5F336A8E4AF2A41DBA4980BEB90D9CD" x="48.1640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g3402EB21D38B9A8AFC4DFC6262792511" x="60.205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="66.2255859375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9E9C649267338B7BCF3BB51B9816396A" x="72.24609375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="78.2666015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="84.287109375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gC5F336A8E4AF2A41DBA4980BEB90D9CD" x="90.3076171875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDAC4E5B9EA78940BD8041CFC64F1642E" x="102.3486328125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="108.369140625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g952AB916CC2FCD530DE73925A36C7F0D" x="120.41015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="126.4306640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g3402EB21D38B9A8AFC4DFC6262792511" x="132.451171875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="138.4716796875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="144.4921875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g23E41626515445E1BB7071D28C59ADA4" x="150.5126953125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="156.533203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDAC4E5B9EA78940BD8041CFC64F1642E" x="162.5537109375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="168.57421875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="174.5947265625" y="0" fill="#000000" fill-rule="nonzero"/></g></g></g></g></g><g transform="translate(0 123.18359375)"><g class="typst-group"><g><g transform="translate(5 11.078125)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#gD3E02A90146443F5D1C908F343BC0F25" x="0" y="0" fill="#d73a49" fill-rule="nonzero"/><use xlink:href="#g9A4F7CA79966390D26B2F6FED68DC851" x="4.81640625" y="0" fill="#d73a49" fill-rule="nonzero"/></g></g><g transform="translate(57.1435546875 12.59765625)"><g class="typst-text" transform="scale(1, -1)"><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="0" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="6.0205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g1FA38BF5C517F615C367E61F0044A197" x="12.041015625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="24.08203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g54B52F8AE89AD429D6D3AD95B2D89739" x="30.1025390625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="36.123046875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="42.1435546875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="48.1640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="54.1845703125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="60.205078125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="66.2255859375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="72.24609375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="84.287109375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gBB49C9F26722473D147EE93A203A972A" x="90.3076171875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="96.328125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="102.3486328125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gC5CB98F12AF1494D83D230F6647F5A66" x="108.369140625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="114.3896484375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g1D505C2B8EC47EA4C26743DADEC508A3" x="126.4306640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDAC4E5B9EA78940BD8041CFC64F1642E" x="132.451171875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="138.4716796875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g961CAE06C7AAE8EB428417D81D5AEE72" x="150.5126953125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="156.533203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="162.5537109375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="168.57421875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="174.5947265625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="180.615234375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g23E41626515445E1BB7071D28C59ADA4" x="186.6357421875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gC5F336A8E4AF2A41DBA4980BEB90D9CD" x="192.65625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g3402EB21D38B9A8AFC4DFC6262792511" x="204.697265625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="210.7177734375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9E9C649267338B7BCF3BB51B9816396A" x="216.73828125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gF1D16D3439F586916205801D07D97589" x="222.7587890625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8EFE1C4A2E0CD0A03B7633D0C324134A" x="228.779296875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g23E41626515445E1BB7071D28C59ADA4" x="234.7998046875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gC5F336A8E4AF2A41DBA4980BEB90D9CD" x="240.8203125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g37BF1C0F714F2658F35D194C9E053C6F" x="252.861328125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="258.8818359375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g3402EB21D38B9A8AFC4DFC6262792511" x="264.90234375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g952AB916CC2FCD530DE73925A36C7F0D" x="276.943359375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDDF33CCACF8520FD5879FCDAE37BD86" x="282.9638671875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g3402EB21D38B9A8AFC4DFC6262792511" x="288.984375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="295.0048828125" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="301.025390625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g23E41626515445E1BB7071D28C59ADA4" x="307.0458984375" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gAB79A30431405AF14CCB1B23143BD7F1" x="313.06640625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#gDAC4E5B9EA78940BD8041CFC64F1642E" x="319.0869140625" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g8B1CFD5A71F51FD444694A31ACE7ED10" x="325.107421875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g9CEA08D585A10BDF30AE748A6F2738E3" x="331.1279296875" y="0" fill="#000000" fill-rule="nonzero"/><use xlink:href="#g23E41626515445E1BB7071D28C59ADA4" x="337.1484375" y="0" fill="#000000" fill-rule="nonzero"/></g></g></g></g></g></g></g></g></g><defs id="glyph"><symbol id="gA9630BC7DC7C1A3B2772AC4EAF5E6A4E" overflow="visible"><path d="M 1.9482422 6.479492 L 1.9482422 3.7402344 L 3.0908203 3.7402344 Q 3.774414 3.7402344 4.157715 4.1015625 Q 4.5410156 4.4628906 4.5410156 5.1123047 Q 4.5410156 5.7617188 4.1601563 6.1206055 Q 3.7792969 6.479492 3.0908203 6.479492 L 1.9482422 6.479492 Z M 0.96191406 7.290039 L 3.0908203 7.290039 Q 4.3115234 7.290039 4.9414063 6.73584 Q 5.571289 6.1816406 5.571289 5.1123047 Q 5.571289 4.033203 4.9438477 3.4814453 Q 4.3164063 2.9296875 3.0908203 2.9296875 L 1.9482422 2.9296875 L 1.9482422 0 L 0.96191406 0 L 0.96191406 7.290039 Z "/></symbol><symbol id="g37BF1C0F714F2658F35D194C9E053C6F" overflow="visible"><path d="M 3.4277344 2.7490234 L 3.1298828 2.7490234 Q 2.34375 2.7490234 1.9458008 2.4731445 Q 1.5478516 2.1972656 1.5478516 1.6503906 Q 1.5478516 1.1572266 1.8457031 0.88378906 Q 2.1435547 0.61035156 2.6708984 0.61035156 Q 3.413086 0.61035156 3.8378906 1.1254883 Q 4.2626953 1.640625 4.267578 2.5488281 L 4.267578 2.7490234 L 3.4277344 2.7490234 Z M 5.1708984 3.1201172 L 5.1708984 0 L 4.267578 0 L 4.267578 0.8105469 Q 3.9794922 0.32226563 3.5424805 0.09033203 Q 3.1054688 -0.14160156 2.4804688 -0.14160156 Q 1.6455078 -0.14160156 1.1474609 0.32958984 Q 0.64941406 0.80078125 0.64941406 1.5917969 Q 0.64941406 2.5048828 1.262207 2.9785156 Q 1.875 3.4521484 3.0615234 3.4521484 L 4.267578 3.4521484 L 4.267578 3.59375 Q 4.2626953 4.248047 3.9355469 4.543457 Q 3.6083984 4.838867 2.890625 4.838867 Q 2.4316406 4.838867 1.9628906 4.7070313 Q 1.4941406 4.5751953 1.0498047 4.321289 L 1.0498047 5.2197266 Q 1.5478516 5.4101563 2.0043945 5.505371 Q 2.4609375 5.600586 2.890625 5.600586 Q 3.569336 5.600586 4.050293 5.4003906 Q 4.53125 5.2001953 4.8291016 4.7998047 Q 5.0146484 4.555664 5.0927734 4.1967773 Q 5.1708984 3.8378906 5.1708984 3.1201172 Z "/></symbol><symbol id="g8EFE1C4A2E0CD0A03B7633D0C324134A" overflow="visible"><path d="M 2.9980469 7.0214844 L 2.9980469 5.46875 L 5.0390625 5.46875 L 5.0390625 4.770508 L 2.9980469 4.770508 L 2.9980469 1.8017578 Q 2.9980469 1.1962891 3.227539 0.95703125 Q 3.4570313 0.71777344 4.0283203 0.71777344 L 5.0390625 0.71777344 L 5.0390625 0 L 3.9404297 0 Q 2.9296875 0 2.5146484 0.40527344 Q 2.0996094 0.8105469 2.0996094 1.8017578 L 2.0996094 4.770508 L 0.63964844 4.770508 L 0.63964844 5.46875 L 2.0996094 5.46875 L 2.0996094 7.0214844 L 2.9980469 7.0214844 Z "/></symbol><symbol id="g9CEA08D585A10BDF30AE748A6F2738E3" overflow="visible"><path d="M 5.4296875 2.9589844 L 5.4296875 2.5195313 L 1.5380859 2.5195313 L 1.5380859 2.4902344 Q 1.5380859 1.5966797 2.0043945 1.1083984 Q 2.4707031 0.6201172 3.3203125 0.6201172 Q 3.75 0.6201172 4.21875 0.75683594 Q 4.6875 0.8935547 5.2197266 1.171875 L 5.2197266 0.2783203 Q 4.7070313 0.068359375 4.230957 -0.036621094 Q 3.7548828 -0.14160156 3.3105469 -0.14160156 Q 2.0361328 -0.14160156 1.3183594 0.6225586 Q 0.60058594 1.3867188 0.60058594 2.7294922 Q 0.60058594 4.038086 1.3037109 4.819336 Q 2.006836 5.600586 3.178711 5.600586 Q 4.223633 5.600586 4.82666 4.892578 Q 5.4296875 4.1845703 5.4296875 2.9589844 Z M 4.53125 3.2226563 Q 4.5117188 4.013672 4.157715 4.4262695 Q 3.803711 4.838867 3.1396484 4.838867 Q 2.4902344 4.838867 2.0703125 4.4091797 Q 1.6503906 3.9794922 1.5722656 3.2177734 L 4.53125 3.2226563 Z "/></symbol><symbol id="g8B1CFD5A71F51FD444694A31ACE7ED10" overflow="visible"><path d="M 5.6396484 4.3408203 Q 5.3515625 4.5654297 5.053711 4.6679688 Q 4.7558594 4.770508 4.399414 4.770508 Q 3.5595703 4.770508 3.1152344 4.243164 Q 2.6708984 3.7158203 2.6708984 2.7197266 L 2.6708984 0 L 1.7675781 0 L 1.7675781 5.46875 L 2.6708984 5.46875 L 2.6708984 4.399414 Q 2.8955078 4.9804688 3.3618164 5.2905273 Q 3.828125 5.600586 4.4677734 5.600586 Q 4.7998047 5.600586 5.0878906 5.517578 Q 5.3759766 5.4345703 5.6396484 5.258789 L 5.6396484 4.3408203 Z "/></symbol><symbol id="gDDF33CCACF8520FD5879FCDAE37BD86" overflow="visible"><path d="M 5.131836 3.3886719 L 5.131836 0 L 4.2285156 0 L 4.2285156 3.3886719 Q 4.2285156 4.1259766 3.9697266 4.4726563 Q 3.7109375 4.819336 3.1591797 4.819336 Q 2.5292969 4.819336 2.1899414 4.3725586 Q 1.8505859 3.9257813 1.8505859 3.0908203 L 1.8505859 0 L 0.95214844 0 L 0.95214844 5.46875 L 1.8505859 5.46875 L 1.8505859 4.6484375 Q 2.0898438 5.1171875 2.5 5.3588867 Q 2.9101563 5.600586 3.4716797 5.600586 Q 4.3066406 5.600586 4.7192383 5.0512695 Q 5.131836 4.501953 5.131836 3.3886719 Z "/></symbol><symbol id="gF2D21C82F46AFB157CA5E1AB14665E2F" overflow="visible"><path d="M 2.1289063 0.8105469 Q 3.3740234 0.8105469 3.8671875 1.4233398 Q 4.3603516 2.0361328 4.3603516 3.6376953 Q 4.3603516 5.2539063 3.869629 5.866699 Q 3.3789063 6.479492 2.1289063 6.479492 L 1.6601563 6.479492 L 1.6601563 0.8105469 L 2.1289063 0.8105469 Z M 2.1484375 7.290039 Q 3.8183594 7.290039 4.609375 6.401367 Q 5.4003906 5.5126953 5.4003906 3.6376953 Q 5.4003906 1.7724609 4.609375 0.88623047 Q 3.8183594 0 2.1484375 0 L 0.6689453 0 L 0.6689453 7.290039 L 2.1484375 7.290039 Z "/></symbol><symbol id="g23E41626515445E1BB7071D28C59ADA4" overflow="visible"><path d="M 4.7509766 5.2783203 L 4.7509766 4.399414 Q 4.3652344 4.6240234 3.9746094 4.736328 Q 3.5839844 4.848633 3.178711 4.848633 Q 2.5683594 4.848633 2.2680664 4.650879 Q 1.9677734 4.453125 1.9677734 4.0478516 Q 1.9677734 3.6816406 2.1923828 3.5009766 Q 2.4169922 3.3203125 3.3105469 3.149414 L 3.671875 3.0810547 Q 4.3408203 2.9541016 4.6850586 2.5732422 Q 5.029297 2.1923828 5.029297 1.5820313 Q 5.029297 0.7714844 4.453125 0.3149414 Q 3.8769531 -0.14160156 2.8515625 -0.14160156 Q 2.446289 -0.14160156 2.0019531 -0.056152344 Q 1.5576172 0.029296875 1.0400391 0.20019531 L 1.0400391 1.1279297 Q 1.5429688 0.8691406 2.0019531 0.7397461 Q 2.4609375 0.61035156 2.8710938 0.61035156 Q 3.4667969 0.61035156 3.7939453 0.8520508 Q 4.1210938 1.09375 4.1210938 1.5283203 Q 4.1210938 2.1533203 2.9248047 2.3925781 L 2.8857422 2.4023438 L 2.5488281 2.4707031 Q 1.7724609 2.6220703 1.4160156 2.980957 Q 1.0595703 3.3398438 1.0595703 3.959961 Q 1.0595703 4.7460938 1.5917969 5.17334 Q 2.1240234 5.600586 3.1103516 5.600586 Q 3.5498047 5.600586 3.9550781 5.5200195 Q 4.3603516 5.439453 4.7509766 5.2783203 Z "/></symbol><symbol id="gAB79A30431405AF14CCB1B23143BD7F1" overflow="visible"><path d="M 5.180664 0.2783203 Q 4.819336 0.068359375 4.436035 -0.036621094 Q 4.0527344 -0.14160156 3.6523438 -0.14160156 Q 2.3828125 -0.14160156 1.6674805 0.6201172 Q 0.95214844 1.3818359 0.95214844 2.7294922 Q 0.95214844 4.0771484 1.6674805 4.838867 Q 2.3828125 5.600586 3.6523438 5.600586 Q 4.0478516 5.600586 4.423828 5.498047 Q 4.7998047 5.395508 5.180664 5.180664 L 5.180664 4.2382813 Q 4.8242188 4.555664 4.465332 4.6972656 Q 4.1064453 4.838867 3.6523438 4.838867 Q 2.8076172 4.838867 2.3535156 4.291992 Q 1.8994141 3.7451172 1.8994141 2.7294922 Q 1.8994141 1.71875 2.355957 1.1694336 Q 2.8125 0.6201172 3.6523438 0.6201172 Q 4.1210938 0.6201172 4.4921875 0.76416016 Q 4.8632813 0.9082031 5.180664 1.2109375 L 5.180664 0.2783203 Z "/></symbol><symbol id="gF1D16D3439F586916205801D07D97589" overflow="visible"><path d="M 1.25 5.46875 L 3.5498047 5.46875 L 3.5498047 0.6982422 L 5.3320313 0.6982422 L 5.3320313 0 L 0.8691406 0 L 0.8691406 0.6982422 L 2.6513672 0.6982422 L 2.6513672 4.770508 L 1.25 4.770508 L 1.25 5.46875 Z M 2.6513672 7.5976563 L 3.5498047 7.5976563 L 3.5498047 6.459961 L 2.6513672 6.459961 L 2.6513672 7.5976563 Z "/></symbol><symbol id="gC5CB98F12AF1494D83D230F6647F5A66" overflow="visible"><path d="M 1.8310547 0.68847656 L 1.8310547 -2.0800781 L 0.9277344 -2.0800781 L 0.9277344 5.46875 L 1.8310547 5.46875 L 1.8310547 4.770508 Q 2.055664 5.1757813 2.4291992 5.3881836 Q 2.8027344 5.600586 3.2910156 5.600586 Q 4.2822266 5.600586 4.8461914 4.8339844 Q 5.4101563 4.067383 5.4101563 2.709961 Q 5.4101563 1.3769531 4.84375 0.6176758 Q 4.2773438 -0.14160156 3.2910156 -0.14160156 Q 2.7929688 -0.14160156 2.4194336 0.07080078 Q 2.0458984 0.28320313 1.8310547 0.68847656 Z M 4.4677734 2.7294922 Q 4.4677734 3.774414 4.1381836 4.3066406 Q 3.8085938 4.838867 3.1591797 4.838867 Q 2.5048828 4.838867 2.1679688 4.304199 Q 1.8310547 3.7695313 1.8310547 2.7294922 Q 1.8310547 1.6943359 2.1679688 1.1572266 Q 2.5048828 0.6201172 3.1591797 0.6201172 Q 3.8085938 0.6201172 4.1381836 1.1523438 Q 4.4677734 1.6845703 4.4677734 2.7294922 Z "/></symbol><symbol id="gDAC4E5B9EA78940BD8041CFC64F1642E" overflow="visible"><path d="M 3.0078125 4.838867 Q 2.3242188 4.838867 1.9726563 4.3066406 Q 1.6210938 3.774414 1.6210938 2.7294922 Q 1.6210938 1.6894531 1.9726563 1.1547852 Q 2.3242188 0.6201172 3.0078125 0.6201172 Q 3.696289 0.6201172 4.0478516 1.1547852 Q 4.399414 1.6894531 4.399414 2.7294922 Q 4.399414 3.774414 4.0478516 4.3066406 Q 3.696289 4.838867 3.0078125 4.838867 Z M 3.0078125 5.600586 Q 4.145508 5.600586 4.748535 4.8632813 Q 5.3515625 4.1259766 5.3515625 2.7294922 Q 5.3515625 1.328125 4.7509766 0.5932617 Q 4.1503906 -0.14160156 3.0078125 -0.14160156 Q 1.8701172 -0.14160156 1.2695313 0.5932617 Q 0.6689453 1.328125 0.6689453 2.7294922 Q 0.6689453 4.1259766 1.2695313 4.8632813 Q 1.8701172 5.600586 3.0078125 5.600586 Z "/></symbol><symbol id="gE671651E4E76A7E6A66592123F7CB0EF" overflow="visible"><path d="M 1.9101563 1.1914063 L 2.8945313 1.1914063 L 2.8945313 0 L 1.9101563 0 L 1.9101563 1.1914063 Z "/></symbol><symbol id="g1FA38BF5C517F615C367E61F0044A197" overflow="visible"><path d="M 4.189453 1.7578125 Q 3.9648438 1.1865234 3.618164 0.25390625 Q 3.1347656 -1.0351563 2.96875 -1.3183594 Q 2.7441406 -1.6992188 2.4072266 -1.8896484 Q 2.0703125 -2.0800781 1.6210938 -2.0800781 L 0.8984375 -2.0800781 L 0.8984375 -1.328125 L 1.4306641 -1.328125 Q 1.8261719 -1.328125 2.0507813 -1.0986328 Q 2.2753906 -0.8691406 2.6220703 0.087890625 L 0.5078125 5.46875 L 1.4599609 5.46875 L 3.0810547 1.1914063 L 4.6777344 5.46875 L 5.629883 5.46875 L 4.189453 1.7578125 Z "/></symbol><symbol id="g54B52F8AE89AD429D6D3AD95B2D89739" overflow="visible"><path d="M 5.131836 3.3886719 L 5.131836 0 L 4.2285156 0 L 4.2285156 3.3886719 Q 4.2285156 4.1259766 3.9697266 4.4726563 Q 3.7109375 4.819336 3.1591797 4.819336 Q 2.5292969 4.819336 2.1899414 4.3725586 Q 1.8505859 3.9257813 1.8505859 3.0908203 L 1.8505859 0 L 0.95214844 0 L 0.95214844 7.5976563 L 1.8505859 7.5976563 L 1.8505859 4.6484375 Q 2.0898438 5.1171875 2.5 5.3588867 Q 2.9101563 5.600586 3.4716797 5.600586 Q 4.3066406 5.600586 4.7192383 5.0512695 Q 5.131836 4.501953 5.131836 3.3886719 Z "/></symbol><symbol id="gBB49C9F26722473D147EE93A203A972A" overflow="visible"><path d="M 5.4589844 5.46875 L 3.5009766 2.8515625 L 5.649414 0 L 4.609375 0 L 3.0078125 2.1923828 L 1.4111328 0 L 0.37109375 0 L 2.5195313 2.8515625 L 0.56152344 5.46875 L 1.5576172 5.46875 L 3.0078125 3.491211 L 4.448242 5.46875 L 5.4589844 5.46875 Z "/></symbol><symbol id="g1D505C2B8EC47EA4C26743DADEC508A3" overflow="visible"><path d="M 5.1904297 7.5976563 L 5.1904297 6.850586 L 4.169922 6.850586 Q 3.6865234 6.850586 3.4985352 6.652832 Q 3.3105469 6.455078 3.3105469 5.9521484 L 3.3105469 5.46875 L 5.1904297 5.46875 L 5.1904297 4.770508 L 3.3105469 4.770508 L 3.3105469 0 L 2.4121094 0 L 2.4121094 4.770508 L 0.95214844 4.770508 L 0.95214844 5.46875 L 2.4121094 5.46875 L 2.4121094 5.8496094 Q 2.4121094 6.748047 2.824707 7.1728516 Q 3.2373047 7.5976563 4.111328 7.5976563 L 5.1904297 7.5976563 Z "/></symbol><symbol id="g961CAE06C7AAE8EB428417D81D5AEE72" overflow="visible"><path d="M 3.1201172 1.9824219 Q 3.1201172 1.3769531 3.3422852 1.0693359 Q 3.5644531 0.76171875 3.9990234 0.76171875 L 5.048828 0.76171875 L 5.048828 0 L 3.9111328 0 Q 3.1054688 0 2.6635742 0.5175781 Q 2.2216797 1.0351563 2.2216797 1.9824219 L 2.2216797 6.948242 L 0.78125 6.948242 L 0.78125 7.651367 L 3.1201172 7.651367 L 3.1201172 1.9824219 Z "/></symbol><symbol id="g77AA3201A93C8F4113E19CCDA185B6F5" overflow="visible"><path d="M 4.482422 2.7294922 Q 4.482422 3.774414 4.1503906 4.3066406 Q 3.8183594 4.838867 3.1689453 4.838867 Q 2.5146484 4.838867 2.1777344 4.304199 Q 1.8408203 3.7695313 1.8408203 2.7294922 Q 1.8408203 1.6943359 2.1777344 1.1572266 Q 2.5146484 0.6201172 3.1689453 0.6201172 Q 3.8183594 0.6201172 4.1503906 1.1523438 Q 4.482422 1.6845703 4.482422 2.7294922 Z M 1.8408203 4.770508 Q 2.055664 5.1708984 2.434082 5.385742 Q 2.8125 5.600586 3.3105469 5.600586 Q 4.296875 5.600586 4.8632813 4.8413086 Q 5.4296875 4.0820313 5.4296875 2.7490234 Q 5.4296875 1.3964844 4.86084 0.6274414 Q 4.291992 -0.14160156 3.3007813 -0.14160156 Q 2.8125 -0.14160156 2.4389648 0.07080078 Q 2.0654297 0.28320313 1.8408203 0.68847656 L 1.8408203 0 L 0.9423828 0 L 0.9423828 7.5976563 L 1.8408203 7.5976563 L 1.8408203 4.770508 Z "/></symbol><symbol id="g958F64BF87063D7EAFEDE953DDA2BF9F" overflow="visible"><path d="M 1.1523438 7.5976563 L 2.0800781 7.5976563 L 2.0800781 3.1982422 L 4.4384766 5.46875 L 5.5322266 5.46875 L 3.3789063 3.4082031 L 5.8691406 0 L 4.770508 0 L 2.7490234 2.8222656 L 2.0800781 2.1923828 L 2.0800781 0 L 1.1523438 0 L 1.1523438 7.5976563 Z "/></symbol><symbol id="gD3E02A90146443F5D1C908F343BC0F25" overflow="visible"><path d="M 1.1445313 5.8320313 L 4.2148438 -0.7421875 L 3.4726563 -0.7421875 L 0.3984375 5.8320313 L 1.1445313 5.8320313 Z "/></symbol><symbol id="gC58E40CCEEAAE4A011790927FE560B0C" overflow="visible"><path d="M 3.8007813 4.2226563 L 3.8007813 3.5195313 Q 3.4921875 3.6992188 3.1796875 3.7890625 Q 2.8671875 3.8789063 2.5429688 3.8789063 Q 2.0546875 3.8789063 1.8144531 3.7207031 Q 1.5742188 3.5625 1.5742188 3.2382813 Q 1.5742188 2.9453125 1.7539063 2.8007813 Q 1.9335938 2.65625 2.6484375 2.5195313 L 2.9375 2.4648438 Q 3.4726563 2.3632813 3.7480469 2.0585938 Q 4.0234375 1.7539063 4.0234375 1.265625 Q 4.0234375 0.6171875 3.5625 0.25195313 Q 3.1015625 -0.11328125 2.28125 -0.11328125 Q 1.9570313 -0.11328125 1.6015625 -0.044921875 Q 1.2460938 0.0234375 0.83203125 0.16015625 L 0.83203125 0.90234375 Q 1.234375 0.6953125 1.6015625 0.5917969 Q 1.96875 0.48828125 2.296875 0.48828125 Q 2.7734375 0.48828125 3.0351563 0.6816406 Q 3.296875 0.875 3.296875 1.2226563 Q 3.296875 1.7226563 2.3398438 1.9140625 L 2.3085938 1.921875 L 2.0390625 1.9765625 Q 1.4179688 2.0976563 1.1328125 2.3847656 Q 0.84765625 2.671875 0.84765625 3.1679688 Q 0.84765625 3.796875 1.2734375 4.138672 Q 1.6992188 4.4804688 2.4882813 4.4804688 Q 2.8398438 4.4804688 3.1640625 4.4160156 Q 3.4882813 4.3515625 3.8007813 4.2226563 Z "/></symbol><symbol id="g3D5EE249F6894FA38DD21E85E2FD5F05" overflow="visible"><path d="M 0 5.46875 L 0.8886719 5.46875 L 1.8408203 1.0498047 L 2.6220703 3.8720703 L 3.3886719 3.8720703 L 4.1796875 1.0498047 L 5.131836 5.46875 L 6.020508 5.46875 L 4.741211 0 L 3.881836 0 L 3.0078125 2.9980469 L 2.1386719 0 L 1.2792969 0 L 0 5.46875 Z "/></symbol><symbol id="gF953090ED8E474A6BDB5C112B8614419" overflow="visible"><path d="M 3.953125 5.6328125 L 3.953125 4.8320313 Q 3.59375 5.0625 3.2324219 5.1796875 Q 2.8710938 5.296875 2.5039063 5.296875 Q 1.9453125 5.296875 1.6210938 5.0371094 Q 1.296875 4.7773438 1.296875 4.3359375 Q 1.296875 3.9492188 1.5097656 3.7460938 Q 1.7226563 3.5429688 2.3046875 3.40625 L 2.71875 3.3125 Q 3.5390625 3.1210938 3.9140625 2.7109375 Q 4.2890625 2.3007813 4.2890625 1.59375 Q 4.2890625 0.76171875 3.7734375 0.32421875 Q 3.2578125 -0.11328125 2.2734375 -0.11328125 Q 1.8632813 -0.11328125 1.4492188 -0.025390625 Q 1.0351563 0.0625 0.6171875 0.23828125 L 0.6171875 1.078125 Q 1.0664063 0.79296875 1.4667969 0.66015625 Q 1.8671875 0.52734375 2.2734375 0.52734375 Q 2.8710938 0.52734375 3.203125 0.7949219 Q 3.5351563 1.0625 3.5351563 1.5429688 Q 3.5351563 1.9804688 3.3066406 2.2109375 Q 3.078125 2.4414063 2.5117188 2.5664063 L 2.0898438 2.6640625 Q 1.2773438 2.8476563 0.91015625 3.21875 Q 0.54296875 3.5898438 0.54296875 4.2148438 Q 0.54296875 4.9960938 1.0683594 5.466797 Q 1.59375 5.9375 2.4648438 5.9375 Q 2.8007813 5.9375 3.171875 5.861328 Q 3.5429688 5.7851563 3.953125 5.6328125 Z "/></symbol><symbol id="gF5F7ADACD3C8648021D0891B6403D353" overflow="visible"><path d="M 3.3515625 3.8164063 L 3.3515625 6.078125 L 4.0703125 6.078125 L 4.0703125 0 L 3.3515625 0 L 3.3515625 0.55078125 Q 3.171875 0.2265625 2.8730469 0.056640625 Q 2.5742188 -0.11328125 2.1835938 -0.11328125 Q 1.390625 -0.11328125 0.9355469 0.5019531 Q 0.48046875 1.1171875 0.48046875 2.1992188 Q 0.48046875 3.265625 0.9375 3.8730469 Q 1.3945313 4.4804688 2.1835938 4.4804688 Q 2.578125 4.4804688 2.8789063 4.310547 Q 3.1796875 4.140625 3.3515625 3.8164063 Z M 1.2382813 2.1835938 Q 1.2382813 1.3476563 1.5039063 0.921875 Q 1.7695313 0.49609375 2.2890625 0.49609375 Q 2.8085938 0.49609375 3.0800781 0.92578125 Q 3.3515625 1.3554688 3.3515625 2.1835938 Q 3.3515625 3.015625 3.0800781 3.4433594 Q 2.8085938 3.8710938 2.2890625 3.8710938 Q 1.7695313 3.8710938 1.5039063 3.4453125 Q 1.2382813 3.0195313 1.2382813 2.1835938 Z "/></symbol><symbol id="g3402EB21D38B9A8AFC4DFC6262792511" overflow="visible"><path d="M 4.189453 4.770508 L 4.189453 7.5976563 L 5.0878906 7.5976563 L 5.0878906 0 L 4.189453 0 L 4.189453 0.68847656 Q 3.9648438 0.28320313 3.5913086 0.07080078 Q 3.2177734 -0.14160156 2.7294922 -0.14160156 Q 1.7382813 -0.14160156 1.1694336 0.6274414 Q 0.60058594 1.3964844 0.60058594 2.7490234 Q 0.60058594 4.0820313 1.171875 4.8413086 Q 1.7431641 5.600586 2.7294922 5.600586 Q 3.2226563 5.600586 3.5986328 5.3881836 Q 3.9746094 5.1757813 4.189453 4.770508 Z M 1.5478516 2.7294922 Q 1.5478516 1.6845703 1.8798828 1.1523438 Q 2.211914 0.6201172 2.8613281 0.6201172 Q 3.5107422 0.6201172 3.8500977 1.1572266 Q 4.189453 1.6943359 4.189453 2.7294922 Q 4.189453 3.7695313 3.8500977 4.304199 Q 3.5107422 4.838867 2.8613281 4.838867 Q 2.211914 4.838867 1.8798828 4.3066406 Q 1.5478516 3.774414 1.5478516 2.7294922 Z "/></symbol><symbol id="g9E9C649267338B7BCF3BB51B9816396A" overflow="visible"><path d="M 4.189453 2.7783203 Q 4.189453 3.7890625 3.8598633 4.313965 Q 3.5302734 4.838867 2.9003906 4.838867 Q 2.241211 4.838867 1.8945313 4.313965 Q 1.5478516 3.7890625 1.5478516 2.7783203 Q 1.5478516 1.7675781 1.8969727 1.237793 Q 2.2460938 0.7080078 2.9101563 0.7080078 Q 3.5302734 0.7080078 3.8598633 1.2402344 Q 4.189453 1.7724609 4.189453 2.7783203 Z M 5.0878906 0.3515625 Q 5.0878906 -0.87890625 4.506836 -1.5136719 Q 3.9257813 -2.1484375 2.7978516 -2.1484375 Q 2.4267578 -2.1484375 2.0214844 -2.0800781 Q 1.6162109 -2.0117188 1.2109375 -1.8798828 L 1.2109375 -0.99121094 Q 1.6894531 -1.2158203 2.0800781 -1.3232422 Q 2.4707031 -1.4306641 2.7978516 -1.4306641 Q 3.5253906 -1.4306641 3.8574219 -1.0351563 Q 4.189453 -0.63964844 4.189453 0.21972656 L 4.189453 0.25878906 L 4.189453 0.8691406 Q 3.9746094 0.41015625 3.6035156 0.18554688 Q 3.2324219 -0.0390625 2.7001953 -0.0390625 Q 1.7431641 -0.0390625 1.171875 0.72753906 Q 0.60058594 1.4941406 0.60058594 2.7783203 Q 0.60058594 4.067383 1.171875 4.8339844 Q 1.7431641 5.600586 2.7001953 5.600586 Q 3.227539 5.600586 3.59375 5.390625 Q 3.959961 5.180664 4.189453 4.741211 L 4.189453 5.4492188 L 5.0878906 5.4492188 L 5.0878906 0.3515625 Z "/></symbol><symbol id="gB83FD8DF61FB2E4EAD552878F3E8DD3F" overflow="visible"><path d="M 3.3007813 4.9121094 Q 3.4667969 5.263672 3.7231445 5.432129 Q 3.9794922 5.600586 4.3408203 5.600586 Q 5 5.600586 5.270996 5.090332 Q 5.541992 4.580078 5.541992 3.1689453 L 5.541992 0 L 4.7216797 0 L 4.7216797 3.1298828 Q 4.7216797 4.2871094 4.592285 4.567871 Q 4.4628906 4.848633 4.1210938 4.848633 Q 3.7304688 4.848633 3.5864258 4.54834 Q 3.4423828 4.248047 3.4423828 3.1298828 L 3.4423828 0 L 2.6220703 0 L 2.6220703 3.1298828 Q 2.6220703 4.301758 2.4829102 4.5751953 Q 2.34375 4.848633 1.9824219 4.848633 Q 1.6259766 4.848633 1.4868164 4.54834 Q 1.3476563 4.248047 1.3476563 3.1298828 L 1.3476563 0 L 0.53222656 0 L 0.53222656 5.46875 L 1.3476563 5.46875 L 1.3476563 5 Q 1.5087891 5.2929688 1.7504883 5.4467773 Q 1.9921875 5.600586 2.2998047 5.600586 Q 2.6708984 5.600586 2.9174805 5.4296875 Q 3.1640625 5.258789 3.3007813 4.9121094 Z "/></symbol><symbol id="g807B89443FA0EF4D7A7A613982FE96F6" overflow="visible"><path d="M 2.3583984 3.6621094 Q 2.3583984 3.930664 2.5463867 4.1259766 Q 2.734375 4.321289 2.9980469 4.321289 Q 3.2714844 4.321289 3.4667969 4.1259766 Q 3.6621094 3.930664 3.6621094 3.6621094 Q 3.6621094 3.3886719 3.4692383 3.1982422 Q 3.2763672 3.0078125 2.9980469 3.0078125 Q 2.7246094 3.0078125 2.541504 3.1933594 Q 2.3583984 3.3789063 2.3583984 3.6621094 Z M 3.0078125 6.640625 Q 2.319336 6.640625 1.9799805 5.8984375 Q 1.640625 5.15625 1.640625 3.6376953 Q 1.640625 2.1240234 1.9799805 1.3818359 Q 2.319336 0.63964844 3.0078125 0.63964844 Q 3.7011719 0.63964844 4.0405273 1.3818359 Q 4.379883 2.1240234 4.379883 3.6376953 Q 4.379883 5.15625 4.0405273 5.8984375 Q 3.7011719 6.640625 3.0078125 6.640625 Z M 3.0078125 7.421875 Q 4.1748047 7.421875 4.772949 6.4648438 Q 5.3710938 5.5078125 5.3710938 3.6376953 Q 5.3710938 1.7724609 4.772949 0.8154297 Q 4.1748047 -0.14160156 3.0078125 -0.14160156 Q 1.8408203 -0.14160156 1.2451172 0.8154297 Q 0.64941406 1.7724609 0.64941406 3.6376953 Q 0.64941406 5.5078125 1.2451172 6.4648438 Q 1.8408203 7.421875 3.0078125 7.421875 Z "/></symbol><symbol id="gA06F636B71996BA7070F256843DCE7EE" overflow="visible"><path d="M 2.9101563 3.2324219 Q 3.540039 3.2324219 3.8989258 3.6865234 Q 4.2578125 4.140625 4.2578125 4.9414063 Q 4.2578125 5.7421875 3.8989258 6.196289 Q 3.540039 6.6503906 2.9101563 6.6503906 Q 2.2558594 6.6503906 1.9238281 6.2182617 Q 1.5917969 5.786133 1.5917969 4.9414063 Q 1.5917969 4.091797 1.9213867 3.6621094 Q 2.2509766 3.2324219 2.9101563 3.2324219 Z M 1.1523438 0.15136719 L 1.1523438 1.0595703 Q 1.4599609 0.87890625 1.8066406 0.7836914 Q 2.1533203 0.68847656 2.5292969 0.68847656 Q 3.4667969 0.68847656 3.947754 1.394043 Q 4.428711 2.0996094 4.428711 3.4716797 Q 4.1992188 2.9833984 3.7841797 2.722168 Q 3.3691406 2.4609375 2.8320313 2.4609375 Q 1.7773438 2.4609375 1.1987305 3.1103516 Q 0.6201172 3.7597656 0.6201172 4.951172 Q 0.6201172 6.1279297 1.2133789 6.7749023 Q 1.8066406 7.421875 2.890625 7.421875 Q 4.1601563 7.421875 4.7509766 6.508789 Q 5.341797 5.595703 5.341797 3.6376953 Q 5.341797 1.796875 4.6313477 0.8276367 Q 3.9208984 -0.14160156 2.5683594 -0.14160156 Q 2.211914 -0.14160156 1.8505859 -0.06591797 Q 1.4892578 0.009765625 1.1523438 0.15136719 Z "/></symbol><symbol id="g27C321132E0A6A9E6B99ED77584BAD53" overflow="visible"><path d="M 1.703125 0.6484375 Q 2.6992188 0.6484375 3.09375 1.1386719 Q 3.4882813 1.6289063 3.4882813 2.9101563 Q 3.4882813 4.203125 3.0957031 4.6933594 Q 2.703125 5.1835938 1.703125 5.1835938 L 1.328125 5.1835938 L 1.328125 0.6484375 L 1.703125 0.6484375 Z M 1.71875 5.8320313 Q 3.0546875 5.8320313 3.6875 5.1210938 Q 4.3203125 4.4101563 4.3203125 2.9101563 Q 4.3203125 1.4179688 3.6875 0.7089844 Q 3.0546875 0 1.71875 0 L 0.53515625 0 L 0.53515625 5.8320313 L 1.71875 5.8320313 Z "/></symbol><symbol id="g7342E383B6C704BD4B47D4672216B35D" overflow="visible"><path d="M 0 4.375 L 0.7109375 4.375 L 1.4726563 0.83984375 L 2.0976563 3.0976563 L 2.7109375 3.0976563 L 3.34375 0.83984375 L 4.1054688 4.375 L 4.8164063 4.375 L 3.7929688 0 L 3.1054688 0 L 2.40625 2.3984375 L 1.7109375 0 L 1.0234375 0 L 0 4.375 Z "/></symbol><symbol id="gC5F336A8E4AF2A41DBA4980BEB90D9CD" overflow="visible"><path d="M 2.4511719 1.4794922 L 3.6816406 1.4794922 L 3.6816406 0.46875 L 2.7197266 -1.4013672 L 1.9677734 -1.4013672 L 2.4511719 0.46875 L 2.4511719 1.4794922 Z "/></symbol><symbol id="g952AB916CC2FCD530DE73925A36C7F0D" overflow="visible"><path d="M 0.95214844 2.0703125 L 0.95214844 5.4589844 L 1.8505859 5.4589844 L 1.8505859 2.0703125 Q 1.8505859 1.3330078 2.1118164 0.9863281 Q 2.3730469 0.63964844 2.9199219 0.63964844 Q 3.5546875 0.63964844 3.8916016 1.0864258 Q 4.2285156 1.5332031 4.2285156 2.368164 L 4.2285156 5.4589844 L 5.131836 5.4589844 L 5.131836 0 L 4.2285156 0 L 4.2285156 0.8203125 Q 3.9892578 0.3466797 3.5766602 0.10253906 Q 3.1640625 -0.14160156 2.6123047 -0.14160156 Q 1.7724609 -0.14160156 1.3623047 0.40771484 Q 0.95214844 0.95703125 0.95214844 2.0703125 Z "/></symbol><symbol id="g9A4F7CA79966390D26B2F6FED68DC851" overflow="visible"><path d="M 0 5.8320313 L 0.76953125 5.8320313 L 1.328125 1.0976563 L 1.9921875 4.2304688 L 2.8164063 4.2304688 L 3.4882813 1.0898438 L 4.046875 5.8320313 L 4.8164063 5.8320313 L 3.9453125 0 L 3.1992188 0 L 2.40625 3.4648438 L 1.6171875 0 L 0.87109375 0 L 0 5.8320313 Z "/></symbol></defs></svg>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h4>Anchors</h4>
|
||
<p><code><code style="white-space: pre-wrap"><span style="color: #d73a49">^</span></code></code> is used to assert the beginning of a line in multi-line mode, or the beginning of the string in whole-string mode.</p>
|
||
<p><code><code style="white-space: pre-wrap"><span style="color: #d73a49">$</span></code></code> is used to assert the end of a line in multi-line mode, or the end of the string in whole-string mode.</p>
|
||
<p>The behaviours of these depend on the <a href="#match-options">match options</a></p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3 id="greedy">Greedy VS Lazy</h3>
|
||
<p>Some combinators will either match “lazy”, or “greedy”.</p>
|
||
<p>Lazy is when the engine only matches as many characters required to get to the next step. This should almost always be used.</p>
|
||
<p>Greedy matching is when the engine tries to match as many characters as possible. The problem with this is that it might cause “backtracking”, which happens when the engine goes back in the pattern multiple times to ensure that as many characters as possible where matched. This can cause big performance issues.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h3>Combinators</h3>
|
||
<p>Multiple atoms can be combined together to form more complex patterns.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h4>Chain</h4>
|
||
<p>When two expressions are next to each other, they will be chained together, which means that both will be evaluated in-order.</p>
|
||
<p>Example: <code><code style="white-space: pre-wrap">x<span style="color: #d73a49">\d</span></code></code> matches a <code><code style="white-space: pre-wrap">x</code></code> and then a digit, like for example <code><code style="white-space: pre-wrap">x9</code></code></p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h4>Or</h4>
|
||
<p>Two expressions separated by a <code><code style="white-space: pre-wrap">|</code></code> cause the RegEx engine to first try to match the left side, and only if it fails, it tries the right side instead.</p>
|
||
<p>Note that “or” has a long left and right scope, which means that <code><code style="white-space: pre-wrap">ab<span style="color: #d73a49">|</span>cd</code></code> will match either <code><code style="white-space: pre-wrap">ab</code></code> or <code><code style="white-space: pre-wrap">cd</code></code></p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h4>Or-Not</h4>
|
||
<p>Tries to match the expression on the left to it, but won’t error if it doesn’t succeed.</p>
|
||
<p>Note that “or-not” has a short left scope, which means that <code><code style="white-space: pre-wrap">ab<span style="color: #d73a49">?</span></code></code> will always match <code><code style="white-space: pre-wrap">a</code></code>, and then try to match <code><code style="white-space: pre-wrap">b</code></code></p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h4>Repeated</h4>
|
||
<p>A expression followed by either a <code><code style="white-space: pre-wrap">*</code></code> for <a href="#greedy">greedy</a> repeat, or a <code><code style="white-space: pre-wrap">*?</code></code> for <a href="#greedy">lazy</a> repeat.</p>
|
||
<p>This matches as many times as possible, but can also match the pattern zero times.</p>
|
||
<p>Note that this has a short left scope.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h4>Repeated At Least Once</h4>
|
||
<p>A expression followed by either a <code><code style="white-space: pre-wrap">+</code></code> for <a href="#greedy">greedy</a> repeat, or a <code><code style="white-space: pre-wrap">+?</code></code> for <a href="#greedy">lazy</a> repeat.</p>
|
||
<p>This matches as many times as possible, and at least one time.</p>
|
||
<p>Note that this has a short left scope.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h4 id="non-capture-group">(Non-Capture) Group</h4>
|
||
<p>Groups multiple expressions together for scoping.</p>
|
||
<p>Example: <code><code style="white-space: pre-wrap"><span style="color: #d73a49">(</span><span style="color: #b60157">?:</span>abc<span style="color: #d73a49">)</span></code></code> will just match <code><code style="white-space: pre-wrap">abc</code></code></p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h4>Capture Group</h4>
|
||
<p>Similar to <a href="#non-capture-group">Non-Capture Groups</a> except that they capture the matched text. This allows the matched text of the inner expression to be extracted later.</p>
|
||
<p>Capture group IDs are enumerated from left to right, starting with 1.</p>
|
||
<p>Example: <code><code style="white-space: pre-wrap"><span style="color: #d73a49">(</span>abc<span style="color: #d73a49">)</span>de</code></code> will match <code><code style="white-space: pre-wrap">abcde</code></code>, and store <code><code style="white-space: pre-wrap">abc</code></code> in group 1.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h4>Character Set</h4>
|
||
<p>By surrounding multiple characters in square brackets, the engine will match any of them. Special characters or expressions won’t be parsed inside them, which means that this can also be used to escape characters.</p>
|
||
<p>For example: <code><code style="white-space: pre-wrap"><span style="color: #d73a49">[</span>abc<span style="color: #d73a49">]</span></code></code> will match either <code><code style="white-space: pre-wrap">a</code></code>, <code><code style="white-space: pre-wrap">b</code></code> or <code><code style="white-space: pre-wrap">c</code></code>.</p>
|
||
<p>and <code><code style="white-space: pre-wrap"><span style="color: #d73a49">[</span>ab(?:c)<span style="color: #d73a49">]</span></code></code> will match either <code><code style="white-space: pre-wrap">a</code></code>, <code><code style="white-space: pre-wrap">b</code></code>, <code><code style="white-space: pre-wrap">(</code></code>, <code><code style="white-space: pre-wrap">?</code></code>, <code><code style="white-space: pre-wrap">:</code></code>, <code><code style="white-space: pre-wrap">c</code></code>, or <code><code style="white-space: pre-wrap">)</code></code>.</p>
|
||
<p><a href="#char-groups">Character groups</a> and <a href="#escaped-chars">escaped characters</a> still work inside character sets.</p>
|
||
<p>Character sets can also contain ranges. For example: <code><code style="white-space: pre-wrap"><span style="color: #d73a49">[</span><span style="color: #b60157">0</span><span style="color: #b60157">-9</span><span style="color: #b60157">a</span><span style="color: #b60157">-z</span><span style="color: #d73a49">]</span></code></code> will match either any digit, or any lowercase letter.</p>
|
||
</div>
|
||
<div style="
|
||
|
||
|
||
|
||
|
||
">
|
||
<p><br></p>
|
||
<h2>Conclusion</h2>
|
||
<p>RegEx is perfect for when you just want to match some patterns, but the syntax can make patterns very hard to read or modify.</p>
|
||
<p>In the next article, we will start to dive into implementing RegEx.</p>
|
||
<p>Stay tuned!</p>
|
||
</div>
|
||
</body>
|
||
</html>
|
||
</content><link href="article-make-regex-engine-1.typ.desktop.html"/><summary>Do you also think that all RegEx engines kinda suck and you want to make your own? probably not</summary></entry></feed> |